1
Fork 0
mirror of https://github.com/RGBCube/alejandra synced 2025-07-30 12:07:46 +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 = [
"clap",
"indoc",
"rand",
"rayon",
"rnix",
"rowan 0.15.3",
@ -129,6 +130,17 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "hashbrown"
version = "0.9.1"
@ -230,6 +242,52 @@ dependencies = [
"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]]
name = "rayon"
version = "1.5.1"
@ -372,6 +430,12 @@ dependencies = [
"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]]
name = "winapi"
version = "0.3.9"

View file

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

View file

@ -55,13 +55,6 @@
Coverage is currently 80%,
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**
Formatting many times yields the same results.
@ -70,9 +63,6 @@
Beauty is subjective, right?
Yet there are a few improvements to implement like:
- Multiline strings indentation is missing `'' ... ''`.
Style is negotiable at this moment.
## Getting started

View file

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

View file

@ -65,6 +65,17 @@ impl Children {
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 {
self.current_index < self.children.len()
}

View file

@ -26,82 +26,113 @@ pub fn rule(
}
}
} else {
let indentation = get_double_quoted_string_indentation(&node);
let placeholder = get_placeholder();
while let Some(child) = children.peek_next() {
match child.element.kind() {
let elements: Vec<rnix::SyntaxElement> = children
.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 => {
let child_token = child.element.into_token().unwrap();
let lines: Vec<&str> =
child_token.text().split('\n').collect();
let token = element.clone().into_token().unwrap();
token.text().to_string()
}
_ => placeholder.to_string(),
})
.collect::<String>()
.split('\n')
.map(|line| line.trim_end().to_string())
.collect();
children.move_next();
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;
}
}
// eprintln!("0: {:?}", lines);
steps.push_back(crate::builder::Step::Token(
rnix::SyntaxKind::TOKEN_STRING_CONTENT,
if indentation >= line.len() {
line.to_string()
} else {
line[indentation..line.len()].to_string()
},
let mut indentation: usize = usize::MAX;
for line in lines.iter() {
let line = line.trim_end();
if line.len() > 0 {
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
}
fn get_double_quoted_string_indentation(node: &rnix::SyntaxNode) -> usize {
let mut indentation: usize = usize::MAX;
fn get_placeholder() -> String {
use rand::RngCore;
let text: String = node
.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();
let mut bytes = [0u8; 32];
for line in text.split('\n') {
let line = line.trim_end();
rand::thread_rng().fill_bytes(&mut bytes);
if line.len() > 0 {
indentation =
usize::min(indentation, line.len() - line.trim_start().len());
}
}
if indentation == usize::MAX { 0 } else { indentation }
bytes.iter().map(|byte| format!("{:02X}", byte)).collect()
}

View file

@ -1,40 +1,62 @@
[
""
###
"
"
###
"a
${x}
b
"
###
''''
###
''a''
###
''${""}''
###
''${""}
''
###
''a
''
###
''a
''
###
'' a
''
###
''a
''
###
''
a
${""}
${""}
b
${""}
c ${""} d
e
''
###
''
''
###
''
declare -a makefiles=(./*.mak)
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)/' \
-e 's/`\([^`]\+\)`/$(shell \1)/' \
"''${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
${ x }
b
"
''''
''a''
''${ "" }''
###
'' ''
###
'' a''
###
'' ${ "" }''
###
'' ${ "" }
''
a
${ "" }
b
${ "" }
c ${ "" } d
e
''
###
'' a
''
###
'' a
''
###
'' a
''
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[@]}"
''
###
'' a
''
###
''
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 }''
]