@@ -35,21 +35,6 @@ pub enum Profile {
35
35
36
36
static PROFILE_DIR : & str = "src/bootstrap/defaults" ;
37
37
38
- /// A list of historical hashes of `src/etc/rust_analyzer_settings.json`.
39
- /// New entries should be appended whenever this is updated so we can detect
40
- /// outdated vs. user-modified settings files.
41
- static SETTINGS_HASHES : & [ & str ] = & [
42
- "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8" ,
43
- "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922" ,
44
- "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0" ,
45
- "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541" ,
46
- "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923" ,
47
- "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a" ,
48
- "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000" ,
49
- "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d" ,
50
- ] ;
51
- static RUST_ANALYZER_SETTINGS : & str = include_str ! ( "../../../../etc/rust_analyzer_settings.json" ) ;
52
-
53
38
impl Profile {
54
39
fn include_path ( & self , src_path : & Path ) -> PathBuf {
55
40
PathBuf :: from ( format ! ( "{}/{PROFILE_DIR}/config.{}.toml" , src_path. display( ) , self ) )
@@ -533,46 +518,162 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
533
518
Ok ( ( ) )
534
519
}
535
520
536
- /// Sets up or displays `src/etc/rust_analyzer_settings.json`
521
+ /// Handles editor-specific setup differences
522
+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
523
+ enum EditorKind {
524
+ Vscode ,
525
+ Vim ,
526
+ Emacs ,
527
+ Helix ,
528
+ }
529
+
530
+ impl EditorKind {
531
+ fn prompt_user ( ) -> io:: Result < Option < EditorKind > > {
532
+ let prompt_str = "Available editors:
533
+ 1. vscode
534
+ 2. vim
535
+ 3. emacs
536
+ 4. helix
537
+
538
+ Select which editor you would like to set up [default: None]: " ;
539
+
540
+ let mut input = String :: new ( ) ;
541
+ loop {
542
+ print ! ( "{}" , prompt_str) ;
543
+ io:: stdout ( ) . flush ( ) ?;
544
+ input. clear ( ) ;
545
+ io:: stdin ( ) . read_line ( & mut input) ?;
546
+ match input. trim ( ) . to_lowercase ( ) . as_str ( ) {
547
+ "1" | "vscode" => return Ok ( Some ( EditorKind :: Vscode ) ) ,
548
+ "2" | "vim" => return Ok ( Some ( EditorKind :: Vim ) ) ,
549
+ "3" | "emacs" => return Ok ( Some ( EditorKind :: Emacs ) ) ,
550
+ "4" | "helix" => return Ok ( Some ( EditorKind :: Helix ) ) ,
551
+ "" => return Ok ( None ) ,
552
+ _ => {
553
+ eprintln ! ( "ERROR: unrecognized option '{}'" , input. trim( ) ) ;
554
+ eprintln ! ( "NOTE: press Ctrl+C to exit" ) ;
555
+ }
556
+ } ;
557
+ }
558
+ }
559
+
560
+ /// A list of historical hashes of each LSP settings file
561
+ /// New entries should be appended whenever this is updated so we can detect
562
+ /// outdated vs. user-modified settings files.
563
+ fn hashes ( & self ) -> Vec < & str > {
564
+ match self {
565
+ EditorKind :: Vscode | EditorKind :: Vim => vec ! [
566
+ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8" ,
567
+ "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922" ,
568
+ "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0" ,
569
+ "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541" ,
570
+ "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923" ,
571
+ "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a" ,
572
+ "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000" ,
573
+ "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d" ,
574
+ ] ,
575
+ EditorKind :: Emacs => vec ! [
576
+ "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0" ,
577
+ "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45" ,
578
+ ] ,
579
+ EditorKind :: Helix => {
580
+ vec ! [ "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233" ]
581
+ }
582
+ }
583
+ }
584
+
585
+ fn settings_path ( & self , config : & Config ) -> PathBuf {
586
+ config. src . join ( self . settings_short_path ( ) )
587
+ }
588
+
589
+ fn settings_short_path ( & self ) -> PathBuf {
590
+ self . settings_folder ( ) . join ( match self {
591
+ EditorKind :: Vscode => "settings.json" ,
592
+ EditorKind :: Vim => "coc-settings.json" ,
593
+ EditorKind :: Emacs => ".dir-locals.el" ,
594
+ EditorKind :: Helix => "languages.toml" ,
595
+ } )
596
+ }
597
+
598
+ fn settings_folder ( & self ) -> PathBuf {
599
+ match self {
600
+ EditorKind :: Vscode => PathBuf :: from ( ".vscode" ) ,
601
+ EditorKind :: Vim => PathBuf :: from ( ".vim" ) ,
602
+ EditorKind :: Emacs => PathBuf :: new ( ) ,
603
+ EditorKind :: Helix => PathBuf :: from ( ".helix" ) ,
604
+ }
605
+ }
606
+
607
+ fn settings_template ( & self ) -> & str {
608
+ match self {
609
+ EditorKind :: Vscode | EditorKind :: Vim => {
610
+ include_str ! ( "../../../../etc/rust_analyzer_settings.json" )
611
+ }
612
+ EditorKind :: Emacs => include_str ! ( "../../../../etc/rust_analyzer_eglot.el" ) ,
613
+ EditorKind :: Helix => include_str ! ( "../../../../etc/rust_analyzer_helix.toml" ) ,
614
+ }
615
+ }
616
+
617
+ fn backup_extension ( & self ) -> String {
618
+ format ! ( "{}.bak" , self . settings_short_path( ) . extension( ) . unwrap( ) . to_str( ) . unwrap( ) )
619
+ }
620
+ }
621
+
622
+ /// Sets up or displays the LSP config for one of the supported editors
537
623
#[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
538
- pub struct Vscode ;
624
+ pub struct Editor ;
539
625
540
- impl Step for Vscode {
626
+ impl Step for Editor {
541
627
type Output = ( ) ;
542
628
const DEFAULT : bool = true ;
629
+
543
630
fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
544
- run. alias ( "vscode " )
631
+ run. alias ( "editor " )
545
632
}
633
+
546
634
fn make_run ( run : RunConfig < ' _ > ) {
547
635
if run. builder . config . dry_run ( ) {
548
636
return ;
549
637
}
550
638
if let [ cmd] = & run. paths [ ..] {
551
- if cmd. assert_single_path ( ) . path . as_path ( ) . as_os_str ( ) == "vscode " {
552
- run. builder . ensure ( Vscode ) ;
639
+ if cmd. assert_single_path ( ) . path . as_path ( ) . as_os_str ( ) == "editor " {
640
+ run. builder . ensure ( Editor ) ;
553
641
}
554
642
}
555
643
}
644
+
556
645
fn run ( self , builder : & Builder < ' _ > ) -> Self :: Output {
557
646
let config = & builder. config ;
558
647
if config. dry_run ( ) {
559
648
return ;
560
649
}
561
- while !t ! ( create_vscode_settings_maybe( config) ) { }
650
+ match EditorKind :: prompt_user ( ) {
651
+ Ok ( editor_kind) => {
652
+ if let Some ( editor_kind) = editor_kind {
653
+ while !t ! ( create_editor_settings_maybe( config, editor_kind. clone( ) ) ) { }
654
+ } else {
655
+ println ! ( "Ok, skipping editor setup!" ) ;
656
+ }
657
+ }
658
+ Err ( e) => eprintln ! ( "Could not determine the editor: {e}" ) ,
659
+ }
562
660
}
563
661
}
564
662
565
- /// Create a `.vscode/settings.json` file for rustc development, or just print it
663
+ /// Create the recommended editor LSP config file for rustc development, or just print it
566
664
/// If this method should be re-called, it returns `false`.
567
- fn create_vscode_settings_maybe ( config : & Config ) -> io:: Result < bool > {
568
- let ( current_hash, historical_hashes) = SETTINGS_HASHES . split_last ( ) . unwrap ( ) ;
569
- let vscode_settings = config. src . join ( ".vscode" ) . join ( "settings.json" ) ;
570
- // If None, no settings.json exists
665
+ fn create_editor_settings_maybe ( config : & Config , editor : EditorKind ) -> io:: Result < bool > {
666
+ let hashes = editor. hashes ( ) ;
667
+ let ( current_hash, historical_hashes) = hashes. split_last ( ) . unwrap ( ) ;
668
+ let settings_path = editor. settings_path ( config) ;
669
+ let settings_short_path = editor. settings_short_path ( ) ;
670
+ let settings_filename = settings_short_path. to_str ( ) . unwrap ( ) ;
671
+ // If None, no settings file exists
571
672
// If Some(true), is a previous version of settings.json
572
673
// If Some(false), is not a previous version (i.e. user modified)
573
674
// If it's up to date we can just skip this
574
675
let mut mismatched_settings = None ;
575
- if let Ok ( current) = fs:: read_to_string ( & vscode_settings ) {
676
+ if let Ok ( current) = fs:: read_to_string ( & settings_path ) {
576
677
let mut hasher = sha2:: Sha256 :: new ( ) ;
577
678
hasher. update ( & current) ;
578
679
let hash = hex_encode ( hasher. finalize ( ) . as_slice ( ) ) ;
@@ -585,20 +686,21 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> {
585
686
}
586
687
}
587
688
println ! (
588
- "\n x.py can automatically install the recommended `.vscode/settings.json ` file for rustc development"
689
+ "\n x.py can automatically install the recommended `{settings_filename} ` file for rustc development"
589
690
) ;
691
+
590
692
match mismatched_settings {
591
- Some ( true ) => eprintln ! (
592
- "WARNING: existing `.vscode/settings.json ` is out of date, x.py will update it"
593
- ) ,
693
+ Some ( true ) => {
694
+ eprintln ! ( "WARNING: existing `{settings_filename} ` is out of date, x.py will update it" )
695
+ }
594
696
Some ( false ) => eprintln ! (
595
- "WARNING: existing `.vscode/settings.json ` has been modified by user, x.py will back it up and replace it"
697
+ "WARNING: existing `{settings_filename} ` has been modified by user, x.py will back it up and replace it"
596
698
) ,
597
699
_ => ( ) ,
598
700
}
599
- let should_create = match prompt_user (
600
- "Would you like to create/update settings.json ? (Press 'p' to preview values): [y/N]" ,
601
- ) ? {
701
+ let should_create = match prompt_user ( & format ! (
702
+ "Would you like to create/update `{settings_filename}` ? (Press 'p' to preview values): [y/N]"
703
+ ) ) ? {
602
704
Some ( PromptResult :: Yes ) => true ,
603
705
Some ( PromptResult :: Print ) => false ,
604
706
_ => {
@@ -607,28 +709,31 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> {
607
709
}
608
710
} ;
609
711
if should_create {
610
- let path = config. src . join ( ".vscode" ) ;
611
- if !path . exists ( ) {
612
- fs:: create_dir ( & path ) ?;
712
+ let settings_folder_path = config. src . join ( editor . settings_folder ( ) ) ;
713
+ if !settings_folder_path . exists ( ) {
714
+ fs:: create_dir ( settings_folder_path ) ?;
613
715
}
614
716
let verb = match mismatched_settings {
615
717
// exists but outdated, we can replace this
616
718
Some ( true ) => "Updated" ,
617
719
// exists but user modified, back it up
618
720
Some ( false ) => {
619
721
// exists and is not current version or outdated, so back it up
620
- let mut backup = vscode_settings. clone ( ) ;
621
- backup. set_extension ( "json.bak" ) ;
622
- eprintln ! ( "WARNING: copying `settings.json` to `settings.json.bak`" ) ;
623
- fs:: copy ( & vscode_settings, & backup) ?;
722
+ let backup = settings_path. clone ( ) . with_extension ( editor. backup_extension ( ) ) ;
723
+ eprintln ! (
724
+ "WARNING: copying `{}` to `{}`" ,
725
+ settings_path. file_name( ) . unwrap( ) . to_str( ) . unwrap( ) ,
726
+ backup. file_name( ) . unwrap( ) . to_str( ) . unwrap( ) ,
727
+ ) ;
728
+ fs:: copy ( & settings_path, & backup) ?;
624
729
"Updated"
625
730
}
626
731
_ => "Created" ,
627
732
} ;
628
- fs:: write ( & vscode_settings , RUST_ANALYZER_SETTINGS ) ?;
629
- println ! ( "{verb} `.vscode/settings.json`" ) ;
733
+ fs:: write ( & settings_path , editor . settings_template ( ) ) ?;
734
+ println ! ( "{verb} `{}`" , settings_filename ) ;
630
735
} else {
631
- println ! ( "\n {RUST_ANALYZER_SETTINGS}" ) ;
736
+ println ! ( "\n {}" , editor . settings_template ( ) ) ;
632
737
}
633
738
Ok ( should_create)
634
739
}
0 commit comments