2019-06-07 16:30:50 +00:00
use crate ::commands ::autoview ;
2019-06-07 06:34:42 +00:00
use crate ::commands ::classified ::SinkCommand ;
2019-05-24 07:29:16 +00:00
use crate ::commands ::classified ::{
2019-05-26 06:54:41 +00:00
ClassifiedCommand , ClassifiedInputStream , ClassifiedPipeline , ExternalCommand , InternalCommand ,
StreamNext ,
2019-05-24 07:29:16 +00:00
} ;
2019-07-03 17:37:09 +00:00
use crate ::commands ::command ::sink ;
2019-07-04 03:06:43 +00:00
use crate ::commands ::plugin ::JsonRpc ;
2019-07-16 07:08:35 +00:00
use crate ::commands ::plugin ::{ PluginCommand , PluginSink } ;
2019-05-23 04:30:43 +00:00
use crate ::context ::Context ;
crate use crate ::errors ::ShellError ;
2019-05-28 06:45:18 +00:00
use crate ::evaluate ::Scope ;
2019-07-03 17:37:09 +00:00
use crate ::git ::current_branch ;
use crate ::object ::Value ;
2019-06-22 03:43:37 +00:00
use crate ::parser ::registry ;
2019-07-03 17:37:09 +00:00
use crate ::parser ::registry ::CommandConfig ;
2019-06-23 17:35:43 +00:00
use crate ::parser ::{ Pipeline , PipelineElement , TokenNode } ;
2019-07-03 17:37:09 +00:00
use crate ::prelude ::* ;
2019-05-23 04:30:43 +00:00
2019-06-22 03:43:37 +00:00
use log ::{ debug , trace } ;
2019-07-04 03:06:43 +00:00
use regex ::Regex ;
2019-05-23 04:30:43 +00:00
use rustyline ::error ::ReadlineError ;
use rustyline ::{ self , ColorMode , Config , Editor } ;
2019-07-03 17:37:09 +00:00
use std ::env ;
2019-05-23 04:30:43 +00:00
use std ::error ::Error ;
2019-07-03 17:37:09 +00:00
use std ::io ::{ BufRead , BufReader , Write } ;
2019-05-24 07:29:16 +00:00
use std ::iter ::Iterator ;
2019-06-07 00:31:22 +00:00
use std ::sync ::atomic ::{ AtomicBool , Ordering } ;
2019-05-23 04:30:43 +00:00
#[ derive(Debug) ]
pub enum MaybeOwned < ' a , T > {
Owned ( T ) ,
Borrowed ( & ' a T ) ,
}
impl < T > MaybeOwned < ' a , T > {
2019-07-04 05:11:56 +00:00
pub fn borrow ( & self ) -> & T {
2019-05-23 04:30:43 +00:00
match self {
MaybeOwned ::Owned ( v ) = > v ,
MaybeOwned ::Borrowed ( v ) = > v ,
}
}
}
2019-07-04 03:06:43 +00:00
fn load_plugin ( path : & std ::path ::Path , context : & mut Context ) -> Result < ( ) , ShellError > {
let mut child = std ::process ::Command ::new ( path )
2019-07-03 17:37:09 +00:00
. stdin ( std ::process ::Stdio ::piped ( ) )
. stdout ( std ::process ::Stdio ::piped ( ) )
. spawn ( )
. expect ( " Failed to spawn child process " ) ;
let stdin = child . stdin . as_mut ( ) . expect ( " Failed to open stdin " ) ;
let stdout = child . stdout . as_mut ( ) . expect ( " Failed to open stdout " ) ;
let mut reader = BufReader ::new ( stdout ) ;
let request = JsonRpc ::new ( " config " , Vec ::< Value > ::new ( ) ) ;
let request_raw = serde_json ::to_string ( & request ) . unwrap ( ) ;
stdin . write ( format! ( " {} \n " , request_raw ) . as_bytes ( ) ) ? ;
2019-07-04 05:11:56 +00:00
let path = dunce ::canonicalize ( path ) . unwrap ( ) ;
2019-07-03 17:37:09 +00:00
let mut input = String ::new ( ) ;
match reader . read_line ( & mut input ) {
Ok ( _ ) = > {
let response =
serde_json ::from_str ::< JsonRpc < Result < CommandConfig , ShellError > > > ( & input ) ;
match response {
Ok ( jrpc ) = > match jrpc . params {
Ok ( params ) = > {
2019-07-04 03:06:43 +00:00
let fname = path . to_string_lossy ( ) ;
2019-07-03 17:37:09 +00:00
if params . is_filter {
let fname = fname . to_string ( ) ;
2019-07-16 07:08:35 +00:00
let name = params . name . clone ( ) ;
context . add_commands ( vec! [ Arc ::new ( PluginCommand ::new (
name , fname , params ,
) ) ] ) ;
2019-07-03 17:37:09 +00:00
Ok ( ( ) )
} else if params . is_sink {
let fname = fname . to_string ( ) ;
2019-07-16 07:08:35 +00:00
let name = params . name . clone ( ) ;
context . add_sinks ( vec! [ Arc ::new ( PluginSink ::new ( name , fname , params ) ) ] ) ;
2019-07-03 17:37:09 +00:00
Ok ( ( ) )
} else {
Ok ( ( ) )
}
}
Err ( e ) = > Err ( e ) ,
} ,
Err ( e ) = > Err ( ShellError ::string ( format! ( " Error: {:?} " , e ) ) ) ,
}
}
Err ( e ) = > Err ( ShellError ::string ( format! ( " Error: {:?} " , e ) ) ) ,
}
}
2019-07-04 03:06:43 +00:00
fn load_plugins_in_dir ( path : & std ::path ::PathBuf , context : & mut Context ) -> Result < ( ) , ShellError > {
let re_bin = Regex ::new ( r "^nu_plugin_[A-Za-z_]+$" ) . unwrap ( ) ;
let re_exe = Regex ::new ( r "^nu_plugin_[A-Za-z_]+\.exe$" ) . unwrap ( ) ;
match std ::fs ::read_dir ( path ) {
Ok ( p ) = > {
for entry in p {
let entry = entry . unwrap ( ) ;
let filename = entry . file_name ( ) ;
let f_name = filename . to_string_lossy ( ) ;
if re_bin . is_match ( & f_name ) | | re_exe . is_match ( & f_name ) {
let mut load_path = path . clone ( ) ;
load_path . push ( f_name . to_string ( ) ) ;
load_plugin ( & load_path , context ) ? ;
}
}
}
_ = > { }
}
Ok ( ( ) )
}
2019-07-03 17:37:09 +00:00
fn load_plugins ( context : & mut Context ) -> Result < ( ) , ShellError > {
match env ::var_os ( " PATH " ) {
Some ( paths ) = > {
for path in env ::split_paths ( & paths ) {
2019-07-04 03:06:43 +00:00
let _ = load_plugins_in_dir ( & path , context ) ;
2019-07-03 17:37:09 +00:00
}
}
None = > println! ( " PATH is not defined in the environment. " ) ,
}
// Also use our debug output for now
let mut path = std ::path ::PathBuf ::from ( " . " ) ;
path . push ( " target " ) ;
path . push ( " debug " ) ;
2019-07-04 03:06:43 +00:00
let _ = load_plugins_in_dir ( & path , context ) ;
2019-07-03 17:37:09 +00:00
2019-07-04 22:17:18 +00:00
// Also use our release output for now
let mut path = std ::path ::PathBuf ::from ( " . " ) ;
path . push ( " target " ) ;
path . push ( " release " ) ;
let _ = load_plugins_in_dir ( & path , context ) ;
2019-07-03 17:37:09 +00:00
Ok ( ( ) )
}
2019-06-03 03:48:58 +00:00
pub async fn cli ( ) -> Result < ( ) , Box < dyn Error > > {
2019-05-23 04:30:43 +00:00
let mut context = Context ::basic ( ) ? ;
{
use crate ::commands ::* ;
context . add_commands ( vec! [
2019-07-03 17:37:09 +00:00
command ( " ps " , Box ::new ( ps ::ps ) ) ,
command ( " ls " , Box ::new ( ls ::ls ) ) ,
command ( " cd " , Box ::new ( cd ::cd ) ) ,
command ( " first " , Box ::new ( first ::first ) ) ,
command ( " size " , Box ::new ( size ::size ) ) ,
2019-07-19 20:11:49 +00:00
command ( " from-csv " , Box ::new ( from_csv ::from_csv ) ) ,
2019-07-03 17:37:09 +00:00
command ( " from-ini " , Box ::new ( from_ini ::from_ini ) ) ,
command ( " from-json " , Box ::new ( from_json ::from_json ) ) ,
command ( " from-toml " , Box ::new ( from_toml ::from_toml ) ) ,
command ( " from-xml " , Box ::new ( from_xml ::from_xml ) ) ,
command ( " from-yaml " , Box ::new ( from_yaml ::from_yaml ) ) ,
command ( " get " , Box ::new ( get ::get ) ) ,
command ( " exit " , Box ::new ( exit ::exit ) ) ,
command ( " lines " , Box ::new ( lines ::lines ) ) ,
command ( " pick " , Box ::new ( pick ::pick ) ) ,
command ( " split-column " , Box ::new ( split_column ::split_column ) ) ,
command ( " split-row " , Box ::new ( split_row ::split_row ) ) ,
command ( " lines " , Box ::new ( lines ::lines ) ) ,
command ( " reject " , Box ::new ( reject ::reject ) ) ,
command ( " trim " , Box ::new ( trim ::trim ) ) ,
command ( " to-array " , Box ::new ( to_array ::to_array ) ) ,
2019-07-21 07:08:05 +00:00
command ( " to-csv " , Box ::new ( to_csv ::to_csv ) ) ,
2019-07-03 17:37:09 +00:00
command ( " to-json " , Box ::new ( to_json ::to_json ) ) ,
command ( " to-toml " , Box ::new ( to_toml ::to_toml ) ) ,
2019-07-16 04:03:28 +00:00
command ( " to-yaml " , Box ::new ( to_yaml ::to_yaml ) ) ,
2019-07-03 17:37:09 +00:00
command ( " sort-by " , Box ::new ( sort_by ::sort_by ) ) ,
2019-08-01 03:25:59 +00:00
command ( " tags " , Box ::new ( tags ::tags ) ) ,
2019-07-17 19:51:18 +00:00
Arc ::new ( Remove ) ,
2019-07-22 02:23:02 +00:00
Arc ::new ( Copycp ) ,
2019-06-22 03:43:37 +00:00
Arc ::new ( Open ) ,
2019-07-26 04:09:19 +00:00
Arc ::new ( Date ) ,
2019-05-28 06:45:18 +00:00
Arc ::new ( Where ) ,
2019-06-01 05:50:16 +00:00
Arc ::new ( Config ) ,
2019-06-18 00:39:09 +00:00
Arc ::new ( SkipWhile ) ,
2019-05-23 04:30:43 +00:00
] ) ;
2019-06-07 06:34:42 +00:00
2019-06-07 07:50:26 +00:00
context . add_sinks ( vec! [
2019-07-03 17:37:09 +00:00
sink ( " autoview " , Box ::new ( autoview ::autoview ) ) ,
sink ( " clip " , Box ::new ( clip ::clip ) ) ,
sink ( " save " , Box ::new ( save ::save ) ) ,
sink ( " table " , Box ::new ( table ::table ) ) ,
sink ( " vtable " , Box ::new ( vtable ::vtable ) ) ,
2019-06-07 07:50:26 +00:00
] ) ;
2019-05-23 04:30:43 +00:00
}
2019-07-04 03:06:43 +00:00
let _ = load_plugins ( & mut context ) ;
2019-05-23 04:30:43 +00:00
2019-05-26 06:54:41 +00:00
let config = Config ::builder ( ) . color_mode ( ColorMode ::Forced ) . build ( ) ;
let h = crate ::shell ::Helper ::new ( context . clone_commands ( ) ) ;
let mut rl : Editor < crate ::shell ::Helper > = Editor ::with_config ( config ) ;
#[ cfg(windows) ]
{
let _ = ansi_term ::enable_ansi_support ( ) ;
}
rl . set_helper ( Some ( h ) ) ;
2019-06-03 00:03:40 +00:00
let _ = rl . load_history ( " history.txt " ) ;
2019-05-26 06:54:41 +00:00
2019-06-07 00:31:22 +00:00
let ctrl_c = Arc ::new ( AtomicBool ::new ( false ) ) ;
let cc = ctrl_c . clone ( ) ;
ctrlc ::set_handler ( move | | {
cc . store ( true , Ordering ::SeqCst ) ;
} )
. expect ( " Error setting Ctrl-C handler " ) ;
2019-06-15 18:36:17 +00:00
let mut ctrlcbreak = false ;
2019-05-23 04:30:43 +00:00
loop {
2019-06-07 00:31:22 +00:00
if ctrl_c . load ( Ordering ::SeqCst ) {
ctrl_c . store ( false , Ordering ::SeqCst ) ;
continue ;
}
2019-07-16 19:10:25 +00:00
let cwd = {
2019-06-13 21:47:25 +00:00
let env = context . env . lock ( ) . unwrap ( ) ;
2019-07-16 19:10:25 +00:00
env . path ( ) . display ( ) . to_string ( )
2019-06-13 21:47:25 +00:00
} ;
2019-07-16 19:10:25 +00:00
let readline = rl . readline ( & format! (
" {}{}> " ,
cwd ,
match current_branch ( ) {
Some ( s ) = > format! ( " ( {} ) " , s ) ,
None = > " " . to_string ( ) ,
}
) ) ;
2019-05-23 04:30:43 +00:00
2019-05-23 07:23:06 +00:00
match process_line ( readline , & mut context ) . await {
2019-05-23 04:30:43 +00:00
LineResult ::Success ( line ) = > {
rl . add_history_entry ( line . clone ( ) ) ;
}
2019-06-15 18:36:17 +00:00
LineResult ::CtrlC = > {
if ctrlcbreak {
std ::process ::exit ( 0 ) ;
} else {
context
. host
. lock ( )
. unwrap ( )
. stdout ( " CTRL-C pressed (again to quit) " ) ;
ctrlcbreak = true ;
continue ;
}
}
2019-06-18 00:39:09 +00:00
LineResult ::Error ( mut line , err ) = > {
rl . add_history_entry ( line . clone ( ) ) ;
2019-06-03 05:11:21 +00:00
2019-06-24 00:55:31 +00:00
let diag = err . to_diagnostic ( ) ;
let host = context . host . lock ( ) . unwrap ( ) ;
let writer = host . err_termcolor ( ) ;
line . push_str ( " " ) ;
let files = crate ::parser ::Files ::new ( line ) ;
language_reporting ::emit (
& mut writer . lock ( ) ,
& files ,
& diag ,
& language_reporting ::DefaultConfig ,
)
. unwrap ( ) ;
2019-06-18 00:39:09 +00:00
}
2019-05-23 04:30:43 +00:00
LineResult ::Break = > {
break ;
}
2019-06-24 00:55:31 +00:00
LineResult ::FatalError ( _ , err ) = > {
2019-05-23 04:30:43 +00:00
context
. host
2019-05-23 07:23:06 +00:00
. lock ( )
. unwrap ( )
2019-05-23 04:30:43 +00:00
. stdout ( & format! ( " A surprising fatal error occurred. \n {:?} " , err ) ) ;
}
}
2019-06-15 18:36:17 +00:00
ctrlcbreak = false ;
2019-05-23 04:30:43 +00:00
}
rl . save_history ( " history.txt " ) . unwrap ( ) ;
Ok ( ( ) )
}
enum LineResult {
Success ( String ) ,
2019-06-07 22:35:07 +00:00
Error ( String , ShellError ) ,
2019-06-15 18:36:17 +00:00
CtrlC ,
2019-05-23 04:30:43 +00:00
Break ,
#[ allow(unused) ]
2019-06-24 00:55:31 +00:00
FatalError ( String , ShellError ) ,
2019-05-23 04:30:43 +00:00
}
2019-05-24 04:34:43 +00:00
impl std ::ops ::Try for LineResult {
type Ok = Option < String > ;
2019-06-24 00:55:31 +00:00
type Error = ( String , ShellError ) ;
2019-05-24 04:34:43 +00:00
2019-06-24 00:55:31 +00:00
fn into_result ( self ) -> Result < Option < String > , ( String , ShellError ) > {
2019-05-24 04:34:43 +00:00
match self {
LineResult ::Success ( s ) = > Ok ( Some ( s ) ) ,
2019-06-24 00:55:31 +00:00
LineResult ::Error ( string , err ) = > Err ( ( string , err ) ) ,
2019-05-24 04:34:43 +00:00
LineResult ::Break = > Ok ( None ) ,
2019-06-15 18:36:17 +00:00
LineResult ::CtrlC = > Ok ( None ) ,
2019-06-24 00:55:31 +00:00
LineResult ::FatalError ( string , err ) = > Err ( ( string , err ) ) ,
2019-05-24 04:34:43 +00:00
}
}
2019-06-24 00:55:31 +00:00
fn from_error ( v : ( String , ShellError ) ) -> Self {
LineResult ::Error ( v . 0 , v . 1 )
2019-05-24 04:34:43 +00:00
}
fn from_ok ( v : Option < String > ) -> Self {
match v {
None = > LineResult ::Break ,
Some ( v ) = > LineResult ::Success ( v ) ,
}
}
}
2019-05-23 07:23:06 +00:00
async fn process_line ( readline : Result < String , ReadlineError > , ctx : & mut Context ) -> LineResult {
2019-05-23 04:30:43 +00:00
match & readline {
Ok ( line ) if line . trim ( ) = = " " = > LineResult ::Success ( line . clone ( ) ) ,
Ok ( line ) = > {
2019-06-02 16:28:40 +00:00
let result = match crate ::parser ::parse ( & line ) {
2019-05-23 04:30:43 +00:00
Err ( err ) = > {
2019-06-09 17:52:56 +00:00
return LineResult ::Error ( line . clone ( ) , err ) ;
2019-05-23 04:30:43 +00:00
}
Ok ( val ) = > val ,
} ;
2019-05-26 06:54:41 +00:00
debug! ( " === Parsed === " ) ;
debug! ( " {:#?} " , result ) ;
2019-05-24 07:29:16 +00:00
2019-06-24 00:55:31 +00:00
let mut pipeline = classify_pipeline ( & result , ctx , & Text ::from ( line ) )
. map_err ( | err | ( line . clone ( ) , err ) ) ? ;
2019-06-07 06:34:42 +00:00
match pipeline . commands . last ( ) {
Some ( ClassifiedCommand ::Sink ( _ ) ) = > { }
2019-06-07 07:54:52 +00:00
Some ( ClassifiedCommand ::External ( _ ) ) = > { }
2019-06-07 06:34:42 +00:00
_ = > pipeline . commands . push ( ClassifiedCommand ::Sink ( SinkCommand {
2019-07-03 17:37:09 +00:00
command : sink ( " autoview " , Box ::new ( autoview ::autoview ) ) ,
2019-08-05 08:54:29 +00:00
name_span : Span ::unknown ( ) ,
2019-06-22 03:43:37 +00:00
args : registry ::Args {
positional : None ,
named : None ,
2019-06-07 06:34:42 +00:00
} ,
} ) ) ,
}
2019-05-24 07:29:16 +00:00
let mut input = ClassifiedInputStream ::new ( ) ;
2019-05-26 06:54:41 +00:00
let mut iter = pipeline . commands . into_iter ( ) . peekable ( ) ;
2019-05-24 07:29:16 +00:00
loop {
let item : Option < ClassifiedCommand > = iter . next ( ) ;
let next : Option < & ClassifiedCommand > = iter . peek ( ) ;
input = match ( item , next ) {
( None , _ ) = > break ,
2019-06-04 21:42:31 +00:00
( Some ( ClassifiedCommand ::Expr ( _ ) ) , _ ) = > {
2019-06-15 18:36:17 +00:00
return LineResult ::Error (
line . clone ( ) ,
ShellError ::unimplemented ( " Expression-only commands " ) ,
)
2019-06-04 21:42:31 +00:00
}
( _ , Some ( ClassifiedCommand ::Expr ( _ ) ) ) = > {
2019-06-15 18:36:17 +00:00
return LineResult ::Error (
line . clone ( ) ,
ShellError ::unimplemented ( " Expression-only commands " ) ,
)
2019-06-04 21:42:31 +00:00
}
2019-06-15 18:36:17 +00:00
( Some ( ClassifiedCommand ::Sink ( SinkCommand { name_span , .. } ) ) , Some ( _ ) ) = > {
2019-08-05 08:54:29 +00:00
return LineResult ::Error ( line . clone ( ) , ShellError ::labeled_error ( " Commands like table, save, and autoview must come last in the pipeline " , " must come last " , name_span ) ) ;
2019-06-07 06:34:42 +00:00
}
( Some ( ClassifiedCommand ::Sink ( left ) ) , None ) = > {
2019-08-01 01:58:42 +00:00
let input_vec : Vec < Tagged < Value > > = input . objects . into_vec ( ) . await ;
2019-06-15 23:03:49 +00:00
if let Err ( err ) = left . run ( ctx , input_vec ) {
return LineResult ::Error ( line . clone ( ) , err ) ;
}
2019-06-07 06:34:42 +00:00
break ;
}
2019-05-24 07:29:16 +00:00
(
Some ( ClassifiedCommand ::Internal ( left ) ) ,
2019-06-07 06:34:42 +00:00
Some ( ClassifiedCommand ::External ( _ ) ) ,
) = > match left . run ( ctx , input ) . await {
Ok ( val ) = > ClassifiedInputStream ::from_input_stream ( val ) ,
2019-06-09 17:52:56 +00:00
Err ( err ) = > return LineResult ::Error ( line . clone ( ) , err ) ,
2019-06-07 06:34:42 +00:00
} ,
2019-06-15 18:36:17 +00:00
( Some ( ClassifiedCommand ::Internal ( left ) ) , Some ( _ ) ) = > {
match left . run ( ctx , input ) . await {
Ok ( val ) = > ClassifiedInputStream ::from_input_stream ( val ) ,
Err ( err ) = > return LineResult ::Error ( line . clone ( ) , err ) ,
}
}
2019-05-24 07:29:16 +00:00
( Some ( ClassifiedCommand ::Internal ( left ) ) , None ) = > {
match left . run ( ctx , input ) . await {
Ok ( val ) = > ClassifiedInputStream ::from_input_stream ( val ) ,
2019-06-09 17:52:56 +00:00
Err ( err ) = > return LineResult ::Error ( line . clone ( ) , err ) ,
2019-05-24 07:29:16 +00:00
}
}
(
Some ( ClassifiedCommand ::External ( left ) ) ,
Some ( ClassifiedCommand ::External ( _ ) ) ,
2019-05-24 18:48:33 +00:00
) = > match left . run ( ctx , input , StreamNext ::External ) . await {
2019-05-24 07:29:16 +00:00
Ok ( val ) = > val ,
2019-06-09 17:52:56 +00:00
Err ( err ) = > return LineResult ::Error ( line . clone ( ) , err ) ,
2019-05-24 07:29:16 +00:00
} ,
2019-06-15 18:36:17 +00:00
( Some ( ClassifiedCommand ::External ( left ) ) , Some ( _ ) ) = > {
match left . run ( ctx , input , StreamNext ::Internal ) . await {
Ok ( val ) = > val ,
Err ( err ) = > return LineResult ::Error ( line . clone ( ) , err ) ,
}
}
2019-05-24 07:29:16 +00:00
( Some ( ClassifiedCommand ::External ( left ) ) , None ) = > {
2019-05-24 18:48:33 +00:00
match left . run ( ctx , input , StreamNext ::Last ) . await {
2019-05-24 07:29:16 +00:00
Ok ( val ) = > val ,
2019-06-09 17:52:56 +00:00
Err ( err ) = > return LineResult ::Error ( line . clone ( ) , err ) ,
2019-05-24 07:29:16 +00:00
}
}
}
2019-05-23 04:30:43 +00:00
}
2019-06-09 17:52:56 +00:00
LineResult ::Success ( line . clone ( ) )
2019-05-23 04:30:43 +00:00
}
2019-06-15 18:36:17 +00:00
Err ( ReadlineError ::Interrupted ) = > LineResult ::CtrlC ,
2019-05-23 04:30:43 +00:00
Err ( ReadlineError ::Eof ) = > {
println! ( " CTRL-D " ) ;
LineResult ::Break
}
Err ( err ) = > {
println! ( " Error: {:?} " , err ) ;
LineResult ::Break
}
}
}
2019-05-26 06:54:41 +00:00
fn classify_pipeline (
2019-06-22 03:43:37 +00:00
pipeline : & TokenNode ,
2019-05-26 06:54:41 +00:00
context : & Context ,
2019-06-22 20:46:16 +00:00
source : & Text ,
2019-05-26 06:54:41 +00:00
) -> Result < ClassifiedPipeline , ShellError > {
2019-06-22 03:43:37 +00:00
let pipeline = pipeline . as_pipeline ( ) ? ;
2019-06-23 17:35:43 +00:00
let Pipeline { parts , .. } = pipeline ;
let commands : Result < Vec < _ > , ShellError > = parts
2019-05-26 06:54:41 +00:00
. iter ( )
2019-06-22 20:46:16 +00:00
. map ( | item | classify_command ( & item , context , & source ) )
2019-05-26 06:54:41 +00:00
. collect ( ) ;
Ok ( ClassifiedPipeline {
commands : commands ? ,
} )
}
2019-05-23 04:30:43 +00:00
fn classify_command (
2019-06-22 03:43:37 +00:00
command : & PipelineElement ,
2019-05-23 04:30:43 +00:00
context : & Context ,
2019-06-22 20:46:16 +00:00
source : & Text ,
2019-05-23 04:30:43 +00:00
) -> Result < ClassifiedCommand , ShellError > {
2019-06-22 03:43:37 +00:00
let call = command . call ( ) ;
2019-06-04 21:42:31 +00:00
2019-06-22 03:43:37 +00:00
match call {
call if call . head ( ) . is_bare ( ) = > {
let head = call . head ( ) ;
let name = head . source ( source ) ;
match context . has_command ( name ) {
2019-06-06 06:34:59 +00:00
true = > {
2019-06-22 03:43:37 +00:00
let command = context . get_command ( name ) ;
2019-06-06 06:34:59 +00:00
let config = command . config ( ) ;
let scope = Scope ::empty ( ) ;
2019-07-12 19:22:08 +00:00
trace! ( target : " nu::build_pipeline " , " classifying {:?} " , config ) ;
2019-06-22 03:43:37 +00:00
let args = config . evaluate_args ( call , context , & scope , source ) ? ;
2019-06-06 06:34:59 +00:00
Ok ( ClassifiedCommand ::Internal ( InternalCommand {
command ,
2019-08-05 08:54:29 +00:00
name_span : head . span ( ) . clone ( ) ,
2019-06-06 06:34:59 +00:00
args ,
} ) )
2019-06-04 21:42:31 +00:00
}
2019-06-22 03:43:37 +00:00
false = > match context . has_sink ( name ) {
2019-06-07 06:34:42 +00:00
true = > {
2019-06-22 03:43:37 +00:00
let command = context . get_sink ( name ) ;
2019-06-07 06:34:42 +00:00
let config = command . config ( ) ;
let scope = Scope ::empty ( ) ;
2019-06-22 03:43:37 +00:00
let args = config . evaluate_args ( call , context , & scope , source ) ? ;
2019-06-07 06:34:42 +00:00
2019-06-07 22:35:07 +00:00
Ok ( ClassifiedCommand ::Sink ( SinkCommand {
command ,
2019-08-05 08:54:29 +00:00
name_span : head . span ( ) . clone ( ) ,
2019-06-07 22:35:07 +00:00
args ,
} ) )
2019-06-07 06:34:42 +00:00
}
false = > {
2019-08-01 01:58:42 +00:00
let arg_list_strings : Vec < Tagged < String > > = match call . children ( ) {
2019-06-22 03:43:37 +00:00
//Some(args) => args.iter().map(|i| i.as_external_arg(source)).collect(),
2019-06-15 04:20:58 +00:00
Some ( args ) = > args
. iter ( )
2019-06-24 00:55:31 +00:00
. filter_map ( | i | match i {
TokenNode ::Whitespace ( _ ) = > None ,
2019-08-05 08:54:29 +00:00
other = > Some ( Tagged ::from_simple_spanned_item (
2019-06-24 00:55:31 +00:00
other . as_external_arg ( source ) ,
other . span ( ) ,
) ) ,
} )
2019-06-15 04:20:58 +00:00
. collect ( ) ,
2019-06-07 06:34:42 +00:00
None = > vec! [ ] ,
} ;
Ok ( ClassifiedCommand ::External ( ExternalCommand {
name : name . to_string ( ) ,
2019-08-05 08:54:29 +00:00
name_span : head . span ( ) . clone ( ) ,
2019-06-07 06:34:42 +00:00
args : arg_list_strings ,
} ) )
}
} ,
2019-06-22 03:43:37 +00:00
}
2019-06-04 21:42:31 +00:00
}
2019-06-22 03:43:37 +00:00
2019-06-24 00:55:31 +00:00
call = > Err ( ShellError ::diagnostic (
language_reporting ::Diagnostic ::new (
language_reporting ::Severity ::Error ,
" Invalid command " ,
)
. with_label ( language_reporting ::Label ::new_primary ( call . head ( ) . span ( ) ) ) ,
2019-06-22 03:43:37 +00:00
) ) ,
2019-05-23 04:30:43 +00:00
}
}