1
Fork 0
mirror of https://github.com/RGBCube/alejandra synced 2025-07-31 12:37:45 +00:00

feat: get strings done right

This commit is contained in:
Kevin Amado 2022-01-27 21:42:40 -05:00
parent e081ba1b4e
commit 08b9b84b14
No known key found for this signature in database
GPG key ID: FFF341057F503148
8 changed files with 253 additions and 101 deletions

64
Cargo.lock generated
View file

@ -8,6 +8,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"indoc", "indoc",
"rand",
"rayon", "rayon",
"rnix", "rnix",
"rowan 0.15.3", "rowan 0.15.3",
@ -129,6 +130,17 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "getrandom"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.9.1" version = "0.9.1"
@ -230,6 +242,52 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "rand"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [
"rand_core",
]
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.5.1" version = "1.5.1"
@ -372,6 +430,12 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View file

@ -1,5 +1,6 @@
[dependencies] [dependencies]
clap = "3" clap = "3"
rand = "0.8"
rayon = "1.5" rayon = "1.5"
rnix = "0.10" rnix = "0.10"
rowan = "0.15" rowan = "0.15"

View file

@ -55,13 +55,6 @@
Coverage is currently 80%, Coverage is currently 80%,
and we'll have 💯% soon. and we'll have 💯% soon.
- ✔️ **Developer aware**
Syntax errors are gracefully handled
by leaving that specific zone unformatted.
The rest of the file will be formatted normally.
- ✔️ **Reproducible** - ✔️ **Reproducible**
Formatting many times yields the same results. Formatting many times yields the same results.
@ -70,9 +63,6 @@
Beauty is subjective, right? Beauty is subjective, right?
Yet there are a few improvements to implement like:
- Multiline strings indentation is missing `'' ... ''`.
Style is negotiable at this moment. Style is negotiable at this moment.
## Getting started ## Getting started

View file

@ -123,7 +123,7 @@ fn build_step(
add_token( add_token(
builder, builder,
build_ctx, build_ctx,
rnix::SyntaxKind::TOKEN_COMMA, rnix::SyntaxKind::TOKEN_WHITESPACE,
&format!("{0:<1$}", "", 2 * build_ctx.indentation), &format!("{0:<1$}", "", 2 * build_ctx.indentation),
); );
} }
@ -209,7 +209,7 @@ fn format(
} }
rnix::SyntaxKind::NODE_ROOT => crate::rules::root::rule, rnix::SyntaxKind::NODE_ROOT => crate::rules::root::rule,
rnix::SyntaxKind::NODE_SELECT => crate::rules::select::rule, rnix::SyntaxKind::NODE_SELECT => crate::rules::select::rule,
rnix::SyntaxKind::NODE_STRING => crate::rules::default, rnix::SyntaxKind::NODE_STRING => crate::rules::string::rule,
rnix::SyntaxKind::NODE_STRING_INTERPOL => { rnix::SyntaxKind::NODE_STRING_INTERPOL => {
crate::rules::string_interpol::rule crate::rules::string_interpol::rule
} }

View file

@ -65,6 +65,17 @@ impl Children {
child child
} }
pub fn get_remaining(&mut self) -> Vec<Child> {
if self.current_index < self.children.len() {
let remaining =
&self.children[self.current_index..self.children.len()];
self.current_index = self.children.len();
remaining.to_vec()
} else {
vec![]
}
}
pub fn has_next(&self) -> bool { pub fn has_next(&self) -> bool {
self.current_index < self.children.len() self.current_index < self.children.len()
} }

View file

@ -26,82 +26,113 @@ pub fn rule(
} }
} }
} else { } else {
let indentation = get_double_quoted_string_indentation(&node); let placeholder = get_placeholder();
while let Some(child) = children.peek_next() { let elements: Vec<rnix::SyntaxElement> = children
match child.element.kind() { .get_remaining()
.iter()
.map(|child| child.element.clone())
.collect();
let mut interpolations = elements
.iter()
.filter(|e| e.kind() != rnix::SyntaxKind::TOKEN_STRING_CONTENT);
let mut lines: Vec<String> = elements[0..elements.len() - 1]
.iter()
.map(|element| match element.kind() {
rnix::SyntaxKind::TOKEN_STRING_CONTENT => { rnix::SyntaxKind::TOKEN_STRING_CONTENT => {
let child_token = child.element.into_token().unwrap(); let token = element.clone().into_token().unwrap();
let lines: Vec<&str> = token.text().to_string()
child_token.text().split('\n').collect(); }
_ => placeholder.to_string(),
})
.collect::<String>()
.split('\n')
.map(|line| line.trim_end().to_string())
.collect();
children.move_next(); // eprintln!("0: {:?}", lines);
for (index, line) in lines.iter().enumerate() {
if index + 1 == lines.len() && line.trim().len() == 0 {
if let rnix::SyntaxKind::TOKEN_STRING_END =
children.peek_next().unwrap().element.kind()
{
continue;
}
}
steps.push_back(crate::builder::Step::Token( let mut indentation: usize = usize::MAX;
rnix::SyntaxKind::TOKEN_STRING_CONTENT, for line in lines.iter() {
if indentation >= line.len() { let line = line.trim_end();
line.to_string()
} else { if line.len() > 0 {
line[indentation..line.len()].to_string() indentation = usize::min(
}, indentation,
line.len() - line.trim_start().len(),
);
}
}
if indentation == usize::MAX {
indentation = 0;
};
// Dedent everything as much as possible
lines = lines
.iter()
.map(|line| {
if indentation < line.len() {
line[indentation..line.len()].to_string()
} else {
line.to_string()
}
})
.collect();
// eprintln!("1: ''{}''", lines.join("\n"));
// eprintln!("indentation={}, placeholder={}", indentation, placeholder);
for (index, line) in lines.iter().enumerate() {
let portions: Vec<String> = line
.split(&placeholder)
.map(|portion| portion.to_string())
.collect();
if portions.len() == 1 {
steps.push_back(crate::builder::Step::Pad);
steps.push_back(crate::builder::Step::Token(
rnix::SyntaxKind::TOKEN_STRING_CONTENT,
portions[0].to_string(),
));
} else {
steps.push_back(crate::builder::Step::Pad);
for (index, portion) in portions.iter().enumerate() {
steps.push_back(crate::builder::Step::Token(
rnix::SyntaxKind::TOKEN_STRING_CONTENT,
portion.to_string(),
));
if index + 1 != portions.len() {
steps.push_back(crate::builder::Step::FormatWider(
interpolations.next().unwrap().clone(),
)); ));
if index == 0 && lines.len() > 1 {
steps.push_back(crate::builder::Step::NewLine);
steps.push_back(crate::builder::Step::Pad);
} else if index + 1 < lines.len()
&& lines[index + 1].trim().len() == 0
{
steps.push_back(crate::builder::Step::NewLine);
steps.push_back(crate::builder::Step::Pad);
}
} }
} }
rnix::SyntaxKind::TOKEN_STRING_END => {
steps
.push_back(crate::builder::Step::Format(child.element));
children.move_next();
}
_ => {
steps.push_back(crate::builder::Step::FormatWider(
child.element,
));
children.move_next();
}
} }
if index + 1 < lines.len() {
steps.push_back(crate::builder::Step::NewLine);
}
}
for interpolation in interpolations {
steps.push_back(crate::builder::Step::FormatWider(
interpolation.clone(),
));
} }
} }
// steps = crate::rules::default(build_ctx, node);
steps steps
} }
fn get_double_quoted_string_indentation(node: &rnix::SyntaxNode) -> usize { fn get_placeholder() -> String {
let mut indentation: usize = usize::MAX; use rand::RngCore;
let text: String = node let mut bytes = [0u8; 32];
.children_with_tokens()
.filter(|child| child.kind() == rnix::SyntaxKind::TOKEN_STRING_CONTENT)
.map(|child| child.into_token().unwrap())
.map(|token| token.text().to_string())
.collect();
for line in text.split('\n') { rand::thread_rng().fill_bytes(&mut bytes);
let line = line.trim_end();
if line.len() > 0 { bytes.iter().map(|byte| format!("{:02X}", byte)).collect()
indentation =
usize::min(indentation, line.len() - line.trim_start().len());
}
}
if indentation == usize::MAX { 0 } else { indentation }
} }

View file

@ -1,40 +1,62 @@
[ [
"" ""
###
" "
" "
###
"a "a
${x} ${x}
b b
" "
###
'''' ''''
###
''a'' ''a''
###
''${""}'' ''${""}''
###
''${""}
''
###
''a
''
###
''a
''
###
'' a
''
###
''a
''
###
'' ''
a a
${""} ${""}
b b
${""} ${""}
c ${""} d c ${""} d
e e
'' ''
###
'' ''
'' ''
###
'' ''
declare -a makefiles=(./*.mak) declare -a makefiles=(./*.mak)
sed -i -f ${makefile-sed} "''${makefiles[@]}" sed -i -f ${makefile-sed} "''${makefiles[@]}"
# assign Makefile variables eagerly & change backticks to `$(shell …)` ### assign Makefile variables eagerly & change backticks to `$(shell …)`
sed -i -e 's/ = `\([^`]\+\)`/ := $(shell \1)/' \ sed -i -e 's/ = `\([^`]\+\)`/ := $(shell \1)/' \
-e 's/`\([^`]\+\)`/$(shell \1)/' \ -e 's/`\([^`]\+\)`/$(shell \1)/' \
"''${makefiles[@]}" "''${makefiles[@]}"
'' ''
###
''
[${ mkSectionName sectName }]
''
###
''-couch_ini ${ cfg.package }/etc/default.ini ${ configFile } ${ pkgs.writeText "couchdb-extra.ini" cfg.extraConfig } ${ cfg.configFile }''
] ]

View file

@ -1,30 +1,63 @@
[ [
"" ""
###
" "
" "
###
"a "a
${ x } ${ x }
b b
" "
'''' ###
''a'' '' ''
''${ "" }'' ###
'' a''
###
'' ${ "" }''
###
'' ${ "" }
'' ''
a ###
${ "" } '' a
b
${ "" }
c ${ "" } d
e
''
'' ''
###
'' a
'' ''
###
'' a
'' ''
declare -a makefiles=(./*.mak) ###
sed -i -f ${ makefile-sed } "''${makefiles[@]}" '' a
# assign Makefile variables eagerly & change backticks to `$(shell …)` ''
sed -i -e 's/ = `\([^`]\+\)`/ := $(shell \1)/' \ ###
-e 's/`\([^`]\+\)`/$(shell \1)/' \ ''
"''${makefiles[@]}" a
'' ${ "" }
b
${ "" }
c ${ "" } d
e
''
###
''
''
###
''
declare -a makefiles=(./*.mak)
sed -i -f ${ makefile-sed } "''${makefiles[@]}"
### assign Makefile variables eagerly & change backticks to `$(shell …)`
sed -i -e 's/ = `\([^`]\+\)`/ := $(shell \1)/' \
-e 's/`\([^`]\+\)`/$(shell \1)/' \
"''${makefiles[@]}"
''
###
''
[${ mkSectionName sectName }]
''
###
'' -couch_ini ${ cfg.package }/etc/default.ini ${ configFile } ${
pkgs.writeText "couchdb-extra.ini" cfg.extraConfig
} ${ cfg.configFile }''
] ]