@@ -9,10 +9,10 @@ use rustpython_compiler::{compile, error::CompileError, error::CompileErrorType}
9
9
use rustpython_parser:: error:: ParseErrorType ;
10
10
use rustpython_vm:: {
11
11
import, match_class,
12
- obj:: { objint:: PyInt , objstr :: PyStringRef , objtuple:: PyTuple , objtype} ,
12
+ obj:: { objint:: PyInt , objtuple:: PyTuple , objtype} ,
13
13
print_exception,
14
- pyobject:: { ItemProtocol , PyIterable , PyObjectRef , PyResult , TryFromObject } ,
15
- scope:: { NameProtocol , Scope } ,
14
+ pyobject:: { ItemProtocol , PyObjectRef , PyResult } ,
15
+ scope:: Scope ,
16
16
util, PySettings , VirtualMachine ,
17
17
} ;
18
18
use std:: convert:: TryInto ;
@@ -22,6 +22,8 @@ use std::path::PathBuf;
22
22
use std:: process;
23
23
use std:: str:: FromStr ;
24
24
25
+ mod shell_helper;
26
+
25
27
fn main ( ) {
26
28
#[ cfg( feature = "flame-it" ) ]
27
29
let main_guard = flame:: start_guard ( "RustPython main" ) ;
@@ -487,154 +489,6 @@ fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> ShellExecResul
487
489
}
488
490
}
489
491
490
- struct ShellHelper < ' a > {
491
- vm : & ' a VirtualMachine ,
492
- scope : Scope ,
493
- }
494
-
495
- impl ShellHelper < ' _ > {
496
- fn complete_opt ( & self , line : & str ) -> Option < ( usize , Vec < String > ) > {
497
- let mut words = vec ! [ String :: new( ) ] ;
498
- fn revlastword ( words : & mut Vec < String > ) {
499
- let word = words. last_mut ( ) . unwrap ( ) ;
500
- let revword = word. chars ( ) . rev ( ) . collect ( ) ;
501
- * word = revword;
502
- }
503
- let mut startpos = 0 ;
504
- for ( i, c) in line. chars ( ) . rev ( ) . enumerate ( ) {
505
- match c {
506
- '.' => {
507
- // check for a double dot
508
- if i != 0 && words. last ( ) . map_or ( false , |s| s. is_empty ( ) ) {
509
- return None ;
510
- }
511
- revlastword ( & mut words) ;
512
- if words. len ( ) == 1 {
513
- startpos = line. len ( ) - i;
514
- }
515
- words. push ( String :: new ( ) ) ;
516
- }
517
- c if c. is_alphanumeric ( ) || c == '_' => words. last_mut ( ) . unwrap ( ) . push ( c) ,
518
- _ => {
519
- if words. len ( ) == 1 {
520
- if words. last ( ) . unwrap ( ) . is_empty ( ) {
521
- return None ;
522
- }
523
- startpos = line. len ( ) - i;
524
- }
525
- break ;
526
- }
527
- }
528
- }
529
- revlastword ( & mut words) ;
530
- words. reverse ( ) ;
531
-
532
- // the very first word and then all the ones after the dot
533
- let ( first, rest) = words. split_first ( ) . unwrap ( ) ;
534
-
535
- let str_iter = |obj| {
536
- PyIterable :: < PyStringRef > :: try_from_object ( self . vm , obj)
537
- . ok ( ) ?
538
- . iter ( self . vm )
539
- . ok ( )
540
- } ;
541
-
542
- type StrIter < ' a > = Box < dyn Iterator < Item = PyResult < PyStringRef > > + ' a > ;
543
-
544
- let ( iter, prefix) = if let Some ( ( last, parents) ) = rest. split_last ( ) {
545
- // we need to get an attribute based off of the dir() of an object
546
-
547
- // last: the last word, could be empty if it ends with a dot
548
- // parents: the words before the dot
549
-
550
- let mut current = self . scope . load_global ( self . vm , first) ?;
551
-
552
- for attr in parents {
553
- current = self . vm . get_attribute ( current. clone ( ) , attr. as_str ( ) ) . ok ( ) ?;
554
- }
555
-
556
- (
557
- Box :: new ( str_iter (
558
- self . vm . call_method ( & current, "__dir__" , vec ! [ ] ) . ok ( ) ?,
559
- ) ?) as StrIter ,
560
- last. as_str ( ) ,
561
- )
562
- } else {
563
- // we need to get a variable based off of globals/builtins
564
-
565
- let globals = str_iter (
566
- self . vm
567
- . call_method ( self . scope . globals . as_object ( ) , "keys" , vec ! [ ] )
568
- . ok ( ) ?,
569
- ) ?;
570
- let iter = if first. as_str ( ) . is_empty ( ) {
571
- // only show globals that don't start with a '_'
572
- Box :: new ( globals. filter ( |r| {
573
- r. as_ref ( )
574
- . ok ( )
575
- . map_or ( true , |s| !s. as_str ( ) . starts_with ( '_' ) )
576
- } ) ) as StrIter
577
- } else {
578
- // show globals and builtins
579
- Box :: new (
580
- globals. chain ( str_iter (
581
- self . vm
582
- . call_method ( & self . vm . builtins , "__dir__" , vec ! [ ] )
583
- . ok ( ) ?,
584
- ) ?) ,
585
- ) as StrIter
586
- } ;
587
- ( iter, first. as_str ( ) )
588
- } ;
589
- let completions = iter
590
- . filter ( |res| {
591
- res. as_ref ( )
592
- . ok ( )
593
- . map_or ( true , |s| s. as_str ( ) . starts_with ( prefix) )
594
- } )
595
- . collect :: < Result < Vec < _ > , _ > > ( )
596
- . ok ( ) ?;
597
- let no_underscore = completions
598
- . iter ( )
599
- . cloned ( )
600
- . filter ( |s| !prefix. starts_with ( '_' ) && !s. as_str ( ) . starts_with ( '_' ) )
601
- . collect :: < Vec < _ > > ( ) ;
602
- let mut completions = if no_underscore. is_empty ( ) {
603
- completions
604
- } else {
605
- no_underscore
606
- } ;
607
- completions. sort_by ( |a, b| std:: cmp:: Ord :: cmp ( a. as_str ( ) , b. as_str ( ) ) ) ;
608
- Some ( (
609
- startpos,
610
- completions
611
- . into_iter ( )
612
- . map ( |s| s. as_str ( ) . to_owned ( ) )
613
- . collect ( ) ,
614
- ) )
615
- }
616
- }
617
-
618
- impl rustyline:: completion:: Completer for ShellHelper < ' _ > {
619
- type Candidate = String ;
620
-
621
- fn complete (
622
- & self ,
623
- line : & str ,
624
- pos : usize ,
625
- _ctx : & rustyline:: Context ,
626
- ) -> rustyline:: Result < ( usize , Vec < String > ) > {
627
- if pos != line. len ( ) {
628
- return Ok ( ( 0 , vec ! [ ] ) ) ;
629
- }
630
- Ok ( self . complete_opt ( line) . unwrap_or ( ( 0 , vec ! [ ] ) ) )
631
- }
632
- }
633
-
634
- impl rustyline:: hint:: Hinter for ShellHelper < ' _ > { }
635
- impl rustyline:: highlight:: Highlighter for ShellHelper < ' _ > { }
636
- impl rustyline:: Helper for ShellHelper < ' _ > { }
637
-
638
492
#[ cfg( not( target_os = "wasi" ) ) ]
639
493
fn run_shell ( vm : & VirtualMachine , scope : Scope ) -> PyResult < ( ) > {
640
494
use rustyline:: { error:: ReadlineError , CompletionType , Config , Editor } ;
@@ -650,10 +504,7 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
650
504
. completion_type ( CompletionType :: List )
651
505
. build ( ) ,
652
506
) ;
653
- repl. set_helper ( Some ( ShellHelper {
654
- vm,
655
- scope : scope. clone ( ) ,
656
- } ) ) ;
507
+ repl. set_helper ( Some ( shell_helper:: ShellHelper :: new ( vm, scope. clone ( ) ) ) ) ;
657
508
let mut full_input = String :: new ( ) ;
658
509
659
510
// Retrieve a `history_path_str` dependent on the OS
0 commit comments