diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /vendor/xflags-macros/src/update.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/xflags-macros/src/update.rs')
-rw-r--r-- | vendor/xflags-macros/src/update.rs | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/vendor/xflags-macros/src/update.rs b/vendor/xflags-macros/src/update.rs new file mode 100644 index 000000000..e476e37aa --- /dev/null +++ b/vendor/xflags-macros/src/update.rs @@ -0,0 +1,98 @@ +use std::{fs, ops::Range, path::Path}; + +pub(crate) fn in_place(api: &str, path: &Path) { + let path = { + let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + Path::new(&dir).join(path) + }; + + let mut text = + fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read {:?}", path)); + + let (insert_to, indent) = locate(&text); + + let api: String = + with_preamble(api) + .lines() + .map(|it| { + if it.trim().is_empty() { + "\n".to_string() + } else { + format!("{}{}\n", indent, it) + } + }) + .collect(); + text.replace_range(insert_to, &api); + + fs::write(&path, text.as_bytes()).unwrap(); +} + +pub(crate) fn stdout(api: &str) { + print!("{}", with_preamble(api)) +} + +fn with_preamble(api: &str) -> String { + format!( + "\ +// generated start +// The following code is generated by `xflags` macro. +// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate. +{} +// generated end +", + api.trim() + ) +} + +fn locate(text: &str) -> (Range<usize>, String) { + if let Some(it) = locate_existing(text) { + return it; + } + if let Some(it) = locate_new(text) { + return it; + } + panic!("failed to update xflags in place") +} + +fn locate_existing(text: &str) -> Option<(Range<usize>, String)> { + let start_idx = text.find("// generated start")?; + let start_idx = newline_before(text, start_idx); + + let end_idx = text.find("// generated end")?; + let end_idx = newline_after(text, end_idx); + + let indent = indent_at(text, start_idx); + + Some((start_idx..end_idx, indent)) +} + +fn newline_before(text: &str, start_idx: usize) -> usize { + text[..start_idx].rfind('\n').map_or(start_idx, |it| it + 1) +} + +fn newline_after(text: &str, start_idx: usize) -> usize { + start_idx + text[start_idx..].find('\n').map_or(text[start_idx..].len(), |it| it + 1) +} + +fn indent_at(text: &str, start_idx: usize) -> String { + text[start_idx..].chars().take_while(|&it| it == ' ').collect() +} + +fn locate_new(text: &str) -> Option<(Range<usize>, String)> { + let mut idx = text.find("xflags!")?; + let mut lvl = 0i32; + for c in text[idx..].chars() { + idx += c.len_utf8(); + match c { + '{' => lvl += 1, + '}' if lvl == 1 => break, + '}' => lvl -= 1, + _ => (), + } + } + let indent = indent_at(text, newline_before(text, idx)); + if text[idx..].starts_with('\n') { + idx += 1; + } + Some((idx..idx, indent)) +} |