From 6e7ac23ee8e7e6486266e3574741ddd2c4605672 Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Wed, 17 Jul 2024 12:25:36 -0400 Subject: [PATCH] Added project-specific Zed IDE settings --- .gitignore | 1 + src/bootstrap/src/core/build_steps/setup.rs | 129 ++++++++++++++++-- src/bootstrap/src/core/builder.rs | 2 +- src/bootstrap/src/core/config/flags.rs | 5 +- src/etc/completions/x.py.sh | 2 +- ...zer_settings.json => vscode_settings.json} | 0 src/etc/zed_settings.json | 48 +++++++ 7 files changed, 172 insertions(+), 15 deletions(-) rename src/etc/{rust_analyzer_settings.json => vscode_settings.json} (100%) create mode 100644 src/etc/zed_settings.json diff --git a/.gitignore b/.gitignore index f1ca6a79b5c5c..24cd8cdbd1ab5 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ Session.vim .idea *.iml .vscode +.zed .project .favorites.json .settings/ diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 29cc5e00637e4..6f15dfa1581c5 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -34,10 +34,10 @@ pub enum Profile { static PROFILE_DIR: &str = "src/bootstrap/defaults"; -/// A list of historical hashes of `src/etc/rust_analyzer_settings.json`. -/// New entries should be appended whenever this is updated so we can detect +/// A list of historical SHA-256 hashes of `src/etc/vscode_settings.json`. New +/// entries should be appended whenever this is updated so we can detect /// outdated vs. user-modified settings files. -static SETTINGS_HASHES: &[&str] = &[ +static VSCODE_SETTINGS_HASHES: &[&str] = &[ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", @@ -46,7 +46,14 @@ static SETTINGS_HASHES: &[&str] = &[ "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", ]; -static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); +static VSCODE_SETTINGS: &str = include_str!("../../../../etc/vscode_settings.json"); + +/// A list of historical SHA-256 hashes of `src/etc/zed_settings.json`. New +/// entries should be appended whenever this is updated so we can detect +/// outdated vs. user-modified settings files. +static ZED_SETTINGS_HASHES: &[&str] = + &["08bb47a0a93947284102eece102cb2e21a91ff952bf21798df92590e31240d98"]; +static ZED_SETTINGS: &str = include_str!("../../../../etc/zed_settings.json"); impl Profile { fn include_path(&self, src_path: &Path) -> PathBuf { @@ -527,11 +534,11 @@ undesirable, simply delete the `pre-push` file from .git/hooks." Ok(()) } -/// Sets up or displays `src/etc/rust_analyzer_settings.json` +/// Sets up or displays `src/etc/vscode_settings.json` #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct Vscode; +pub struct VsCode; -impl Step for Vscode { +impl Step for VsCode { type Output = (); const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -543,7 +550,7 @@ impl Step for Vscode { } if let [cmd] = &run.paths[..] { if cmd.assert_single_path().path.as_path().as_os_str() == "vscode" { - run.builder.ensure(Vscode); + run.builder.ensure(VsCode); } } } @@ -559,7 +566,7 @@ impl Step for Vscode { /// Create a `.vscode/settings.json` file for rustc development, or just print it /// If this method should be re-called, it returns `false`. fn create_vscode_settings_maybe(config: &Config) -> io::Result { - let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap(); + let (current_hash, historical_hashes) = VSCODE_SETTINGS_HASHES.split_last().unwrap(); let vscode_settings = config.src.join(".vscode").join("settings.json"); // If None, no settings.json exists // If Some(true), is a previous version of settings.json @@ -619,10 +626,110 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result { } _ => "Created", }; - fs::write(&vscode_settings, RUST_ANALYZER_SETTINGS)?; + fs::write(&vscode_settings, VSCODE_SETTINGS)?; println!("{verb} `.vscode/settings.json`"); } else { - println!("\n{RUST_ANALYZER_SETTINGS}"); + println!("\n{VSCODE_SETTINGS}"); + } + Ok(should_create) +} + +/// Sets up or displays `src/etc/zed_settings.json` +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct Zed; + +impl Step for Zed { + type Output = (); + const DEFAULT: bool = true; + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("zed") + } + fn make_run(run: RunConfig<'_>) { + if run.builder.config.dry_run() { + return; + } + if let [cmd] = &run.paths[..] { + if cmd.assert_single_path().path.as_path().as_os_str() == "zed" { + run.builder.ensure(Zed); + } + } + } + fn run(self, builder: &Builder<'_>) -> Self::Output { + let config = &builder.config; + if config.dry_run() { + return; + } + while !t!(create_zed_settings_maybe(config)) {} + } +} + +/// Create a `.zed/settings.json` file for rustc development, or just print it +/// If this method should be re-called, it returns `false`. +fn create_zed_settings_maybe(config: &Config) -> io::Result { + let (current_hash, historical_hashes) = ZED_SETTINGS_HASHES.split_last().unwrap(); + let zed_settings = config.src.join(".zed").join("settings.json"); + // If None, no settings.json exists + // If Some(true), is a previous version of settings.json + // If Some(false), is not a previous version (i.e. user modified) + // If it's up to date we can just skip this + let mut mismatched_settings = None; + if let Ok(current) = fs::read_to_string(&zed_settings) { + let mut hasher = sha2::Sha256::new(); + hasher.update(¤t); + let hash = hex_encode(hasher.finalize().as_slice()); + if hash == *current_hash { + return Ok(true); + } else if historical_hashes.contains(&hash.as_str()) { + mismatched_settings = Some(true); + } else { + mismatched_settings = Some(false); + } + } + println!( + "\nx.py can automatically install the recommended `.zed/settings.json` file for rustc development" + ); + match mismatched_settings { + Some(true) => eprintln!( + "WARNING: existing `.zed/settings.json` is out of date, x.py will update it" + ), + Some(false) => eprintln!( + "WARNING: existing `.zed/settings.json` has been modified by user, x.py will back it up and replace it" + ), + _ => (), + } + let should_create = match prompt_user( + "Would you like to create/update settings.json? (Press 'p' to preview values): [y/N]", + )? { + Some(PromptResult::Yes) => true, + Some(PromptResult::Print) => false, + _ => { + println!("Ok, skipping settings!"); + return Ok(true); + } + }; + if should_create { + let path = config.src.join(".zed"); + if !path.exists() { + fs::create_dir(&path)?; + } + let verb = match mismatched_settings { + // exists but outdated, we can replace this + Some(true) => "Updated", + // exists but user modified, back it up + Some(false) => { + // exists and is not current version or outdated, so back it up + let mut backup = zed_settings.clone(); + backup.set_extension("json.bak"); + eprintln!("WARNING: copying `settings.json` to `settings.json.bak`"); + fs::copy(&zed_settings, &backup)?; + "Updated" + } + _ => "Created", + }; + fs::write(&zed_settings, ZED_SETTINGS)?; + println!("{verb} `.zed/settings.json`"); + } else { + println!("\n{ZED_SETTINGS}"); } Ok(should_create) } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index f033905e9f62c..cc57bbfbdb8d0 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -960,7 +960,7 @@ impl<'a> Builder<'a> { run::GenerateWindowsSys, run::GenerateCompletions, ), - Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), + Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::VsCode, setup::Zed), Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 19f752da81c13..cb2a36b54e418 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -443,14 +443,15 @@ Arguments: The profile is optional and you will be prompted interactively if it is not given. The following profiles are available: {} - To only set up the git hook, VS Code config or toolchain link, you may use + To only set up the git hook, VS Code config, Zed config, or toolchain link, you may use ./x.py setup hook ./x.py setup vscode + ./x.py setup zed ./x.py setup link", Profile::all_for_help(" ").trim_end()))] Setup { /// Either the profile for `config.toml` or another setup action. /// May be omitted to set up interactively - #[arg(value_name = "|hook|vscode|link")] + #[arg(value_name = "|hook|vscode|zed|link")] profile: Option, }, /// Suggest a subset of tests to run, based on modified files diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index a4234905476ad..da68b4d5265ad 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -1642,7 +1642,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|zed|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/vscode_settings.json similarity index 100% rename from src/etc/rust_analyzer_settings.json rename to src/etc/vscode_settings.json diff --git a/src/etc/zed_settings.json b/src/etc/zed_settings.json new file mode 100644 index 0000000000000..47f3fa77a8ede --- /dev/null +++ b/src/etc/zed_settings.json @@ -0,0 +1,48 @@ +{ + // The following commented-out VS Code settings are not supported by Zed yet. + // "git.detectSubmodulesLimit": 20 + "lsp": { + "rust-analyzer": { + "initialization_options": { + "check": { + "invocationLocation": "root", + "invocationStrategy": "once", + "overrideCommand": ["python3", "x.py", "check", "--json-output"] + }, + "linkedProjects": [ + "Cargo.toml", + "src/tools/x/Cargo.toml", + "src/bootstrap/Cargo.toml", + "src/tools/rust-analyzer/Cargo.toml", + "compiler/rustc_codegen_cranelift/Cargo.toml", + "compiler/rustc_codegen_gcc/Cargo.toml" + ], + "rustfmt": { + "overrideCommand": [ + "${workspaceFolder}/build/host/rustfmt/bin/rustfmt", + "--edition=2021" + ] + }, + "procMacro": { + "server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv", + "enable": true + }, + "cargo": { + "buildScripts": { + "enable": true, + "invocationLocation": "root", + "invocationStrategy": "once", + "overrideCommand": ["python3", "x.py", "check", "--json-output"] + }, + "sysrootSrc": "./library", + "extraEnv": { + "RUSTC_BOOTSTRAP": "1" + } + }, + "rustc": { + "source": "./Cargo.toml" + } + } + } + } +}