-
Notifications
You must be signed in to change notification settings - Fork 13.5k
bootstrap: Consolidate editor setup into ./x setup editor & add support for vim, emacs & helix #131075
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
bootstrap: Consolidate editor setup into ./x setup editor & add support for vim, emacs & helix #131075
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,21 +35,6 @@ 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 | ||
/// outdated vs. user-modified settings files. | ||
static SETTINGS_HASHES: &[&str] = &[ | ||
"ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", | ||
"56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", | ||
"af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", | ||
"3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", | ||
"47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", | ||
"b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", | ||
"828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", | ||
"811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", | ||
]; | ||
static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); | ||
|
||
impl Profile { | ||
fn include_path(&self, src_path: &Path) -> PathBuf { | ||
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." | |
Ok(()) | ||
} | ||
|
||
/// Sets up or displays `src/etc/rust_analyzer_settings.json` | ||
/// Handles editor-specific setup differences | ||
#[derive(Clone, Debug, Eq, PartialEq)] | ||
enum EditorKind { | ||
Vscode, | ||
Vim, | ||
Emacs, | ||
Helix, | ||
} | ||
|
||
impl EditorKind { | ||
fn prompt_user() -> io::Result<Option<EditorKind>> { | ||
let prompt_str = "Available editors: | ||
1. vscode | ||
2. vim | ||
3. emacs | ||
4. helix | ||
|
||
Select which editor you would like to set up [default: None]: "; | ||
|
||
let mut input = String::new(); | ||
loop { | ||
print!("{}", prompt_str); | ||
io::stdout().flush()?; | ||
input.clear(); | ||
io::stdin().read_line(&mut input)?; | ||
match input.trim().to_lowercase().as_str() { | ||
"1" | "vscode" => return Ok(Some(EditorKind::Vscode)), | ||
"2" | "vim" => return Ok(Some(EditorKind::Vim)), | ||
"3" | "emacs" => return Ok(Some(EditorKind::Emacs)), | ||
"4" | "helix" => return Ok(Some(EditorKind::Helix)), | ||
"" => return Ok(None), | ||
_ => { | ||
eprintln!("ERROR: unrecognized option '{}'", input.trim()); | ||
eprintln!("NOTE: press Ctrl+C to exit"); | ||
} | ||
}; | ||
} | ||
} | ||
|
||
/// A list of historical hashes of each LSP settings file | ||
/// New entries should be appended whenever this is updated so we can detect | ||
/// outdated vs. user-modified settings files. | ||
fn hashes(&self) -> Vec<&str> { | ||
match self { | ||
EditorKind::Vscode | EditorKind::Vim => vec![ | ||
"ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", | ||
"56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", | ||
"af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", | ||
"3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", | ||
"47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", | ||
"b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", | ||
"828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", | ||
"811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", | ||
], | ||
EditorKind::Emacs => vec![ | ||
"51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", | ||
"d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", | ||
], | ||
EditorKind::Helix => { | ||
vec!["2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233"] | ||
} | ||
} | ||
} | ||
|
||
fn settings_path(&self, config: &Config) -> PathBuf { | ||
config.src.join(self.settings_short_path()) | ||
} | ||
|
||
fn settings_short_path(&self) -> PathBuf { | ||
self.settings_folder().join(match self { | ||
EditorKind::Vscode => "settings.json", | ||
EditorKind::Vim => "coc-settings.json", | ||
EditorKind::Emacs => ".dir-locals.el", | ||
EditorKind::Helix => "languages.toml", | ||
}) | ||
} | ||
|
||
fn settings_folder(&self) -> PathBuf { | ||
match self { | ||
EditorKind::Vscode => PathBuf::from(".vscode"), | ||
EditorKind::Vim => PathBuf::from(".vim"), | ||
EditorKind::Emacs => PathBuf::new(), | ||
EditorKind::Helix => PathBuf::from(".helix"), | ||
} | ||
} | ||
|
||
fn settings_template(&self) -> &str { | ||
match self { | ||
EditorKind::Vscode | EditorKind::Vim => { | ||
include_str!("../../../../etc/rust_analyzer_settings.json") | ||
} | ||
EditorKind::Emacs => include_str!("../../../../etc/rust_analyzer_eglot.el"), | ||
EditorKind::Helix => include_str!("../../../../etc/rust_analyzer_helix.toml"), | ||
} | ||
} | ||
|
||
fn backup_extension(&self) -> String { | ||
format!("{}.bak", self.settings_short_path().extension().unwrap().to_str().unwrap()) | ||
} | ||
} | ||
|
||
/// Sets up or displays the LSP config for one of the supported editors | ||
#[derive(Clone, Debug, Eq, PartialEq, Hash)] | ||
pub struct Vscode; | ||
pub struct Editor; | ||
|
||
impl Step for Vscode { | ||
impl Step for Editor { | ||
type Output = (); | ||
const DEFAULT: bool = true; | ||
|
||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | ||
run.alias("vscode") | ||
run.alias("editor") | ||
} | ||
|
||
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() == "vscode" { | ||
run.builder.ensure(Vscode); | ||
if cmd.assert_single_path().path.as_path().as_os_str() == "editor" { | ||
run.builder.ensure(Editor); | ||
} | ||
} | ||
} | ||
|
||
fn run(self, builder: &Builder<'_>) -> Self::Output { | ||
let config = &builder.config; | ||
if config.dry_run() { | ||
return; | ||
} | ||
while !t!(create_vscode_settings_maybe(config)) {} | ||
match EditorKind::prompt_user() { | ||
Ok(editor_kind) => { | ||
if let Some(editor_kind) = editor_kind { | ||
while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: The logic would be simpler to follow if the loop was directly inside But this was pre-existing, so it doesn't need to be changed in this PR. |
||
} else { | ||
println!("Ok, skipping editor setup!"); | ||
} | ||
} | ||
Err(e) => eprintln!("Could not determine the editor: {e}"), | ||
} | ||
} | ||
} | ||
|
||
/// Create a `.vscode/settings.json` file for rustc development, or just print it | ||
/// Create the recommended editor LSP config 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<bool> { | ||
let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap(); | ||
let vscode_settings = config.src.join(".vscode").join("settings.json"); | ||
// If None, no settings.json exists | ||
fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Result<bool> { | ||
let hashes = editor.hashes(); | ||
let (current_hash, historical_hashes) = hashes.split_last().unwrap(); | ||
let settings_path = editor.settings_path(config); | ||
let settings_short_path = editor.settings_short_path(); | ||
let settings_filename = settings_short_path.to_str().unwrap(); | ||
// If None, no settings file 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(&vscode_settings) { | ||
if let Ok(current) = fs::read_to_string(&settings_path) { | ||
let mut hasher = sha2::Sha256::new(); | ||
hasher.update(¤t); | ||
let hash = hex_encode(hasher.finalize().as_slice()); | ||
|
@@ -585,20 +686,21 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> { | |
} | ||
} | ||
println!( | ||
"\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development" | ||
"\nx.py can automatically install the recommended `{settings_filename}` file for rustc development" | ||
); | ||
|
||
match mismatched_settings { | ||
Some(true) => eprintln!( | ||
"WARNING: existing `.vscode/settings.json` is out of date, x.py will update it" | ||
), | ||
Some(true) => { | ||
eprintln!("WARNING: existing `{settings_filename}` is out of date, x.py will update it") | ||
} | ||
Some(false) => eprintln!( | ||
"WARNING: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it" | ||
"WARNING: existing `{settings_filename}` 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]", | ||
)? { | ||
let should_create = match prompt_user(&format!( | ||
"Would you like to create/update `{settings_filename}`? (Press 'p' to preview values): [y/N]" | ||
))? { | ||
Some(PromptResult::Yes) => true, | ||
Some(PromptResult::Print) => false, | ||
_ => { | ||
|
@@ -607,28 +709,31 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> { | |
} | ||
}; | ||
if should_create { | ||
let path = config.src.join(".vscode"); | ||
if !path.exists() { | ||
fs::create_dir(&path)?; | ||
let settings_folder_path = config.src.join(editor.settings_folder()); | ||
if !settings_folder_path.exists() { | ||
fs::create_dir(settings_folder_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 = vscode_settings.clone(); | ||
backup.set_extension("json.bak"); | ||
eprintln!("WARNING: copying `settings.json` to `settings.json.bak`"); | ||
fs::copy(&vscode_settings, &backup)?; | ||
let backup = settings_path.clone().with_extension(editor.backup_extension()); | ||
eprintln!( | ||
"WARNING: copying `{}` to `{}`", | ||
settings_path.file_name().unwrap().to_str().unwrap(), | ||
backup.file_name().unwrap().to_str().unwrap(), | ||
); | ||
fs::copy(&settings_path, &backup)?; | ||
"Updated" | ||
} | ||
_ => "Created", | ||
}; | ||
fs::write(&vscode_settings, RUST_ANALYZER_SETTINGS)?; | ||
println!("{verb} `.vscode/settings.json`"); | ||
fs::write(&settings_path, editor.settings_template())?; | ||
println!("{verb} `{}`", settings_filename); | ||
} else { | ||
println!("\n{RUST_ANALYZER_SETTINGS}"); | ||
println!("\n{}", editor.settings_template()); | ||
} | ||
Ok(should_create) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,17 @@ | ||
use sha2::Digest; | ||
|
||
use super::{RUST_ANALYZER_SETTINGS, SETTINGS_HASHES}; | ||
use super::EditorKind; | ||
use crate::utils::helpers::hex_encode; | ||
|
||
#[test] | ||
fn check_matching_settings_hash() { | ||
let editor = EditorKind::Vscode; | ||
let mut hasher = sha2::Sha256::new(); | ||
hasher.update(&RUST_ANALYZER_SETTINGS); | ||
hasher.update(&editor.settings_template()); | ||
let hash = hex_encode(hasher.finalize().as_slice()); | ||
assert_eq!( | ||
&hash, | ||
SETTINGS_HASHES.last().unwrap(), | ||
"Update `SETTINGS_HASHES` with the new hash of `src/etc/rust_analyzer_settings.json`" | ||
editor.hashes().last().unwrap(), | ||
"Update `EditorKind::hashes()` with the new hash of `src/etc/rust_analyzer_settings.json`" | ||
); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.