diff --git a/examples/readme.rs b/examples/readme.rs index 4f4250343..d7a2363c9 100644 --- a/examples/readme.rs +++ b/examples/readme.rs @@ -11,6 +11,14 @@ fn main() { fn app(cx: Scope) -> Element { let mut count = use_state(&cx, || 0); + let a = rsx! { + div { + + + key: "a" + } + }; + cx.render(rsx! { h1 { "High-Five counter: {count}" } button { onclick: move |_| count += 1, "Up high!" } diff --git a/packages/autofmt/Cargo.toml b/packages/autofmt/Cargo.toml index 8fb7a128f..c7bf01dfa 100644 --- a/packages/autofmt/Cargo.toml +++ b/packages/autofmt/Cargo.toml @@ -12,3 +12,4 @@ syn = { version = "1.0.11", features = ["full", "extra-traits"] } dioxus-rsx = { path = "../rsx" } triple_accel = "0.4.0" serde = { version = "1.0.136", features = ["derive"] } +prettyplease = { git = "https://github.com/DioxusLabs/prettyplease-macro-fmt.git", features = ["verbatim"] } diff --git a/packages/autofmt/src/block.rs b/packages/autofmt/src/block.rs new file mode 100644 index 000000000..d3ef135d9 --- /dev/null +++ b/packages/autofmt/src/block.rs @@ -0,0 +1,94 @@ +use crate::{util::*, write_ident}; +use dioxus_rsx::*; +use std::fmt::Write; +use triple_accel::{levenshtein_search, Match}; + +#[derive(serde::Deserialize, serde::Serialize, Clone, Debug, PartialEq, Hash)] +pub struct FormattedBlock { + pub formatted: String, + pub start: usize, + pub end: usize, +} + +pub fn get_format_blocks(contents: &str) -> Vec { + let matches = levenshtein_search(b"rsx! {", contents.as_bytes()).peekable(); + + let mut formatted_blocks = Vec::new(); + let mut last_bracket_end = 0; + + // find the rsx! marker + for Match { start, end, k } in matches { + // ensure the marker is not nested + if start < last_bracket_end { + continue; + } + + let remaining = &contents[end - 1..]; + let bracket_end = find_bracket_end(remaining).unwrap(); + let sub_string = &contents[end..bracket_end + end - 1]; + last_bracket_end = bracket_end + end - 1; + + let new = fmt_block(sub_string).unwrap(); + + let stripped = &contents[end + 1..bracket_end + end - 1]; + + if stripped == new { + continue; + } + + // if we have code to push, we want the code to end up on the right lines with the right indentation + let mut output = String::new(); + writeln!(output).unwrap(); + + for line in new.lines() { + writeln!(output, "{}", line).ok(); + } + + formatted_blocks.push(FormattedBlock { + formatted: output, + start: end, + end: end + bracket_end - 1, + }); + } + + formatted_blocks +} + +struct Isolate<'a> { + contents: &'a str, + start: usize, + end: usize, +} +fn isolate_body_of_rsx(contents: &str, Match { start, end, k }: triple_accel::Match) -> Isolate { + todo!() +} + +pub fn fmt_block(block: &str) -> Option { + let mut buf = String::new(); + let lines = block.split('\n').collect::>(); + + for node in &syn::parse_str::(block).ok()?.roots { + write_ident(&mut buf, &lines, node, 0).ok()?; + } + + Some(buf) +} + +#[test] +fn format_block_basic() { + let block = r#" + let a = 120; + + rsx! { + div { + h1 { "thing" } + h1 { "thing" } + h1 { "thing" } + } + } + "#; + + let edits = get_format_blocks(block); + + println!("{}", edits[0].formatted); +} diff --git a/packages/autofmt/src/children.rs b/packages/autofmt/src/children.rs new file mode 100644 index 000000000..3b56590bc --- /dev/null +++ b/packages/autofmt/src/children.rs @@ -0,0 +1,4 @@ +// write the body of a component or element +pub fn write_children() { + +} diff --git a/packages/autofmt/src/component.rs b/packages/autofmt/src/component.rs new file mode 100644 index 000000000..df4e14006 --- /dev/null +++ b/packages/autofmt/src/component.rs @@ -0,0 +1,78 @@ +use crate::{util::*, write_ident}; +use dioxus_rsx::*; +use quote::ToTokens; +use std::fmt::{self, Write}; + +pub fn write_component( + component: &Component, + buf: &mut String, + indent: usize, + lines: &[&str], +) -> Result<(), fmt::Error> { + let Component { + name, + body, + children, + manual_props, + prop_gen_args, + } = component; + let mut name = name.to_token_stream().to_string(); + name.retain(|c| !c.is_whitespace()); + write_tabs(buf, indent)?; + write!(buf, "{name}")?; + if let Some(generics) = prop_gen_args { + let mut written = generics.to_token_stream().to_string(); + written.retain(|c| !c.is_whitespace()); + write!(buf, "{}", written)?; + } + write!(buf, " {{")?; + if !body.is_empty() || !children.is_empty() { + writeln!(buf)?; + } + for field in body { + write_tabs(buf, indent + 1)?; + let name = &field.name; + match &field.content { + ContentField::ManExpr(exp) => { + let out = prettyplease::unparse_expr(exp); + writeln!(buf, "{}: {},", name, out)?; + } + ContentField::Formatted(s) => { + writeln!(buf, "{}: \"{}\",", name, s.value())?; + } + ContentField::OnHandlerRaw(exp) => { + let out = prettyplease::unparse_expr(exp); + let mut lines = out.split('\n').peekable(); + let first = lines.next().unwrap(); + write!(buf, "{}: {}", name, first)?; + for line in lines { + writeln!(buf)?; + write_tabs(buf, indent + 1)?; + write!(buf, "{}", line)?; + } + writeln!(buf, ",")?; + } + } + } + if let Some(exp) = manual_props { + write_tabs(buf, indent + 1)?; + let out = prettyplease::unparse_expr(exp); + let mut lines = out.split('\n').peekable(); + let first = lines.next().unwrap(); + write!(buf, "..{}", first)?; + for line in lines { + writeln!(buf)?; + write_tabs(buf, indent + 1)?; + write!(buf, "{}", line)?; + } + writeln!(buf)?; + } + for child in children { + write_ident(buf, lines, child, indent + 1)?; + } + if !body.is_empty() || !children.is_empty() { + write_tabs(buf, indent)?; + } + writeln!(buf, "}}")?; + Ok(()) +} diff --git a/packages/autofmt/src/element.rs b/packages/autofmt/src/element.rs new file mode 100644 index 000000000..bde1c33f8 --- /dev/null +++ b/packages/autofmt/src/element.rs @@ -0,0 +1,160 @@ +use crate::{util::*, write_ident}; +use dioxus_rsx::*; +use std::{fmt, fmt::Write}; + +pub fn write_element( + Element { + name, + key, + attributes, + children, + _is_static, + }: &Element, + buf: &mut String, + lines: &[&str], + node: &BodyNode, + indent: usize, +) -> fmt::Result { + /* + Write the tag + Write the key + Write the attributes + Write the children + */ + + write!(buf, "{name} {{")?; + + let total_attr_len = extract_attr_len(attributes); + let is_long_attr_list = total_attr_len > 80; + + if let Some(key) = key.as_ref().map(|f| f.value()) { + if is_long_attr_list { + writeln!(buf)?; + write_tabs(buf, indent + 1)?; + } else { + write!(buf, " ")?; + } + write!(buf, "key: \"{key}\"")?; + + if !attributes.is_empty() { + write!(buf, ",")?; + } + } + + let mut attr_iter = attributes.iter().peekable(); + + while let Some(attr) = attr_iter.next() { + if is_long_attr_list { + writeln!(buf)?; + write_tabs(buf, indent + 1)?; + } else { + write!(buf, " ")?; + } + + match &attr.attr { + ElementAttr::AttrText { name, value } => { + write!(buf, "{name}: \"{value}\"", value = value.value())?; + } + ElementAttr::AttrExpression { name, value } => { + let out = prettyplease::unparse_expr(value); + write!(buf, "{}: {}", name, out)?; + } + + ElementAttr::CustomAttrText { name, value } => { + write!( + buf, + "\"{name}\": \"{value}\"", + name = name.value(), + value = value.value() + )?; + } + + ElementAttr::CustomAttrExpression { name, value } => { + let out = prettyplease::unparse_expr(value); + write!(buf, "\"{}\": {}", name.value(), out)?; + } + + ElementAttr::EventTokens { name, tokens } => { + let out = prettyplease::unparse_expr(tokens); + + let mut lines = out.split('\n').peekable(); + let first = lines.next().unwrap(); + + // a one-liner for whatever reason + // Does not need a new line + if lines.peek().is_none() { + write!(buf, "{}: {}", name, first)?; + } else { + writeln!(buf, "{}: {}", name, first)?; + + while let Some(line) = lines.next() { + write_tabs(buf, indent + 1)?; + write!(buf, "{}", line)?; + if lines.peek().is_none() { + write!(buf, "")?; + } else { + writeln!(buf)?; + } + } + } + } + } + + if attr_iter.peek().is_some() || !children.is_empty() { + write!(buf, ",")?; + } + } + + // If the attr list is short, then we want to optimize for some cases + let is_child_optimized = match children.as_slice() { + // No children, just close the tag + [] => true, + + // Only a text node, just write it out + [BodyNode::Text(_)] => true, + + // If these have zero children and attributes, then we can just write out the tag + [BodyNode::Component(ref comp)] => comp.body.is_empty() && comp.children.is_empty(), + [BodyNode::Element(ref el)] => el.attributes.is_empty() && el.children.is_empty(), + + // Nothing else is optimized + _ => false, + }; + + if !is_long_attr_list && is_child_optimized { + write_ident(buf, lines, &children[0], indent)?; + } else { + for child in children { + writeln!(buf)?; + write_ident(buf, lines, child, indent + 1)?; + } + } + + // let text_val = text.value(); + // if total_attr_len + text_val.len() > 80 { + // writeln!(buf)?; + // write_tabs(buf, indent + 1)?; + // writeln!(buf, "\"{}\"", text.value())?; + // write_tabs(buf, indent)?; + // } else { + // write!(buf, " \"{}\" ", text.value())?; + // } + + // if is_long_attr_list { + // writeln!(buf)?; + // } + + // for child in children { + // write_ident(buf, lines, child, indent + 1)?; + // } + + // if is_long_attr_list { + // write_tabs(buf, indent)?; + // } else { + // write!(buf, " ")?; + // } + + writeln!(buf, "}}")?; + + Ok(()) +} diff --git a/packages/autofmt/src/expr.rs b/packages/autofmt/src/expr.rs new file mode 100644 index 000000000..7cc0ed17a --- /dev/null +++ b/packages/autofmt/src/expr.rs @@ -0,0 +1,39 @@ +//! pretty printer for rsx! +use std::fmt::{self, Write}; + +pub fn write_raw_expr( + exp: &syn::Expr, + indent: usize, + lines: &[&str], + buf: &mut String, +) -> Result<(), fmt::Error> { + use syn::spanned::Spanned; + let placement = exp.span(); + let start = placement.start(); + let end = placement.end(); + let num_spaces_desired = (indent * 4) as isize; + let first = lines[start.line - 1]; + let num_spaces_real = first.chars().take_while(|c| c.is_whitespace()).count() as isize; + let offset = num_spaces_real - num_spaces_desired; + + for line_id in start.line - 1..end.line { + let line = lines[line_id]; + + // trim the leading whitespace + + if offset < 0 { + for _ in 0..-offset { + write!(buf, " ")?; + } + + writeln!(buf, "{}", line)?; + } else { + let offset = offset as usize; + + let right = &line[offset..]; + writeln!(buf, "{}", right)?; + } + } + + Ok(()) +} diff --git a/packages/autofmt/src/ident.rs b/packages/autofmt/src/ident.rs new file mode 100644 index 000000000..19fd3cb8d --- /dev/null +++ b/packages/autofmt/src/ident.rs @@ -0,0 +1,23 @@ +use crate::{ + component::write_component, element::write_element, expr::write_raw_expr, util::write_tabs, +}; +use dioxus_rsx::*; +use std::fmt::{self, Write}; + +pub fn write_ident( + buf: &mut String, + lines: &[&str], + node: &BodyNode, + indent: usize, +) -> fmt::Result { + match node { + BodyNode::Element(el) => write_element(el, buf, lines, node, indent), + BodyNode::Component(component) => write_component(component, buf, indent, lines), + BodyNode::Text(text) => write_text(text, buf, indent), + BodyNode::RawExpr(exp) => write_raw_expr(exp, indent, lines, buf), + } +} + +fn write_text(text: &syn::LitStr, buf: &mut String, indent: usize) -> fmt::Result { + write!(buf, "\"{}\"", text.value()) +} diff --git a/packages/autofmt/src/lib.rs b/packages/autofmt/src/lib.rs index 4f467e139..c6fd2eeec 100644 --- a/packages/autofmt/src/lib.rs +++ b/packages/autofmt/src/lib.rs @@ -1,413 +1,16 @@ -//! pretty printer for rsx! +//! pretty printer for rsx code + use dioxus_rsx::*; use proc_macro2::TokenStream as TokenStream2; use quote::ToTokens; -use std::{ - fmt::{self, Write}, - ptr::NonNull, -}; -use syn::{ - buffer::TokenBuffer, - parse::{ParseBuffer, ParseStream}, -}; -use triple_accel::{levenshtein_search, Match}; -mod prettyplease; +mod block; +mod children; +mod component; +mod element; +mod expr; +mod ident; +mod util; -#[derive(serde::Deserialize, serde::Serialize, Clone, Debug, PartialEq, Hash)] -pub struct FormattedBlock { - pub formatted: String, - pub start: usize, - pub end: usize, -} - -/* - - -*/ -pub fn get_format_blocks(contents: &str) -> Vec { - let mut matches = levenshtein_search(b"rsx! {", contents.as_bytes()).peekable(); - - let mut cur_match: Option = None; - - let mut formatted_blocks = Vec::new(); - - let mut last_bracket_end = 0; - - for item in matches { - let Match { start, end, k } = item; - - if start < last_bracket_end { - continue; - } - - let remaining = &contents[end - 1..]; - - if let Some(bracket_end) = find_bracket_end(remaining) { - let sub_string = &contents[end..bracket_end + end - 1]; - - last_bracket_end = bracket_end + end - 1; - - // with the edge brackets - // println!("{}", &contents[end - 1..bracket_end + end]); - - if let Some(new) = fmt_block(sub_string) { - if !new.is_empty() { - println!("{}", &contents[end + 1..bracket_end + end - 1]); - println!("{}", new); - - let stripped = &contents[end + 1..bracket_end + end - 1]; - if stripped == new { - println!("no changes necessary"); - } - - // if we have code to push, we want the code to end up on the right lines with the right indentation - - let mut output = String::new(); - writeln!(output).unwrap(); - - for line in new.lines() { - writeln!(output, " {}", line).ok(); - } - - formatted_blocks.push(FormattedBlock { - formatted: output, - start: end, - end: end + bracket_end - 1, - }); - } - } else { - panic!("failed to format block: {}", sub_string); - } - } else { - panic!("failed to find end of block: {}", remaining); - } - } - - formatted_blocks -} - -pub fn fmt_block(block: &str) -> Option { - let mut raw_lines = block.split('\n').collect::>(); - - let parsed: CallBody = syn::parse_str(block).ok()?; - - let mut buf = String::new(); - - for node in parsed.roots.iter() { - write_ident(&mut buf, &raw_lines, node, 0).ok()?; - } - - Some(buf) -} - -pub fn write_ident( - buf: &mut String, - lines: &[&str], - node: &BodyNode, - indent: usize, -) -> fmt::Result { - match node { - BodyNode::Element(el) => { - let Element { - name, - key, - attributes, - children, - _is_static, - } = el; - - write_tabs(buf, indent)?; - write!(buf, "{name} {{")?; - - let total_attr_len = attributes - .iter() - .map(|attr| match &attr.attr { - ElementAttr::AttrText { name, value } => value.value().len(), - ElementAttr::AttrExpression { name, value } => 10, - ElementAttr::CustomAttrText { name, value } => value.value().len(), - ElementAttr::CustomAttrExpression { name, value } => 10, - ElementAttr::EventTokens { name, tokens } => 1000000, - ElementAttr::Meta(_) => todo!(), - }) - .sum::(); - - let is_long_attr_list = total_attr_len > 80; - - if let Some(key) = key { - let key = key.value(); - if is_long_attr_list { - write_tabs(buf, indent + 1)?; - } else { - write!(buf, " ")?; - } - write!(buf, "key: \"{key}\"")?; - - if !attributes.is_empty() { - writeln!(buf, ",")?; - } - } - - let mut attr_iter = attributes.iter().peekable(); - while let Some(attr) = attr_iter.next() { - if is_long_attr_list { - writeln!(buf)?; - write_tabs(buf, indent + 1)?; - } else { - write!(buf, " ")?; - } - - match &attr.attr { - ElementAttr::AttrText { name, value } => { - write!(buf, "{name}: \"{value}\"", value = value.value())?; - } - ElementAttr::AttrExpression { name, value } => { - let out = prettyplease::unparse_expr(value); - write!(buf, "{}: {}", name, out)?; - } - - ElementAttr::CustomAttrText { name, value } => { - write!( - buf, - "\"{name}\": \"{value}\"", - name = name.value(), - value = value.value() - )?; - } - - ElementAttr::CustomAttrExpression { name, value } => { - let out = prettyplease::unparse_expr(value); - write!(buf, "\"{}\": {}", name.value(), out)?; - } - - ElementAttr::EventTokens { name, tokens } => { - let out = prettyplease::unparse_expr(tokens); - - dbg!(&out); - - let mut lines = out.split('\n').peekable(); - let first = lines.next().unwrap(); - - // a one-liner for whatever reason - // Does not need a new line - if lines.peek().is_none() { - write!(buf, "{}: {}", name, first)?; - } else { - writeln!(buf, "{}: {}", name, first)?; - - while let Some(line) = lines.next() { - write_tabs(buf, indent + 1)?; - write!(buf, "{}", line)?; - if lines.peek().is_none() { - write!(buf, "")?; - } else { - writeln!(buf)?; - } - } - } - } - ElementAttr::Meta(_) => {} - } - - if attr_iter.peek().is_some() || !children.is_empty() { - write!(buf, ",")?; - } - } - - if children.len() == 1 && children[0].is_litstr() && !is_long_attr_list { - if let BodyNode::Text(text) = &children[0] { - let text_val = text.value(); - if total_attr_len + text_val.len() > 80 { - writeln!(buf)?; - write_tabs(buf, indent + 1)?; - writeln!(buf, "\"{}\"", text.value())?; - write_tabs(buf, indent)?; - } else { - write!(buf, " \"{}\" ", text.value())?; - } - } - } else { - if is_long_attr_list || !children.is_empty() { - writeln!(buf)?; - } - - for child in children { - write_ident(buf, lines, child, indent + 1)?; - } - - if is_long_attr_list || !children.is_empty() { - write_tabs(buf, indent)?; - } else { - write!(buf, " ")?; - } - } - - writeln!(buf, "}}")?; - } - BodyNode::Component(component) => { - let Component { - name, - body, - children, - manual_props, - } = component; - - let mut name = name.to_token_stream().to_string(); - name.retain(|c| !c.is_whitespace()); - - write_tabs(buf, indent)?; - write!(buf, "{name} {{")?; - - if !body.is_empty() || !children.is_empty() { - writeln!(buf)?; - } - - for field in body { - write_tabs(buf, indent + 1)?; - let name = &field.name; - match &field.content { - ContentField::ManExpr(exp) => { - let out = prettyplease::unparse_expr(exp); - writeln!(buf, "{}: {},", name, out)?; - } - ContentField::Formatted(s) => { - writeln!(buf, "{}: \"{}\",", name, s.value())?; - } - ContentField::OnHandlerRaw(exp) => { - let out = prettyplease::unparse_expr(exp); - let mut lines = out.split('\n').peekable(); - let first = lines.next().unwrap(); - write!(buf, "{}: {}", name, first)?; - for line in lines { - writeln!(buf)?; - write_tabs(buf, indent + 1)?; - write!(buf, "{}", line)?; - } - writeln!(buf, ",")?; - } - } - } - - if let Some(exp) = manual_props { - write_tabs(buf, indent + 1)?; - let out = prettyplease::unparse_expr(exp); - let mut lines = out.split('\n').peekable(); - let first = lines.next().unwrap(); - write!(buf, "..{}", first)?; - for line in lines { - writeln!(buf)?; - write_tabs(buf, indent + 1)?; - write!(buf, "{}", line)?; - } - writeln!(buf)?; - } - - for child in children { - write_ident(buf, lines, child, indent + 1)?; - } - - if !body.is_empty() || !children.is_empty() { - write_tabs(buf, indent)?; - } - - writeln!(buf, "}}")?; - - // - // write!(buf, "{}", " ".repeat(ident)) - } - BodyNode::Text(t) => { - // - // write!(buf, "{}", " ".repeat(ident)) - write_tabs(buf, indent)?; - writeln!(buf, "\"{}\"", t.value())?; - } - BodyNode::RawExpr(exp) => { - use syn::spanned::Spanned; - - let placement = exp.span(); - - let start = placement.start(); - let end = placement.end(); - - let num_spaces_desired = (indent * 4) as isize; - let first = lines[start.line - 1]; - let num_spaces_real = first.chars().take_while(|c| c.is_whitespace()).count() as isize; - let offset = num_spaces_real - num_spaces_desired; - - for line_id in start.line - 1..end.line { - let line = lines[line_id]; - - // trim the leading whitespace - - if offset < 0 { - for _ in 0..-offset { - write!(buf, " ")?; - } - - writeln!(buf, "{}", line)?; - } else { - let offset = offset as usize; - - let right = &line[offset..]; - writeln!(buf, "{}", right)?; - } - } - - // let toks = exp.to_token_stream(); - - // let out = prettyplease::unparse_expr(exp); - // let mut lines = out.split('\n').peekable(); - // for line in lines { - // write_tabs(buf, indent)?; - // writeln!(buf, "{}", line)?; - // // writeln!(buf)?; - // } - // write_tabs(buf, indent)?; - // let first = lines.next().unwrap(); - // write!(buf, "{}", name, first)?; - // writeln!(buf)?; - - // - // write!(buf, "{}", " ".repeat(ident)) - } - BodyNode::Meta(att) => { - // - // if att.path.segments.last().unwrap().ident == "doc" { - let val = att.to_string(); - write_tabs(buf, indent)?; - writeln!(buf, "{}", val)?; - // } - // match att {} - } - } - - Ok(()) -} - -pub fn write_tabs(f: &mut dyn Write, num: usize) -> std::fmt::Result { - for _ in 0..num { - write!(f, " ")? - } - Ok(()) -} - -fn find_bracket_end(contents: &str) -> Option { - let mut depth = 0; - let mut i = 0; - - for c in contents.chars() { - if c == '{' { - depth += 1; - } else if c == '}' { - depth -= 1; - } - - if depth == 0 { - return Some(i); - } - - i += 1; - } - - None -} +pub use block::{fmt_block, get_format_blocks}; +pub use ident::write_ident; diff --git a/packages/autofmt/src/prettyplease/algorithm.rs b/packages/autofmt/src/prettyplease/algorithm.rs deleted file mode 100644 index b70bd57ea..000000000 --- a/packages/autofmt/src/prettyplease/algorithm.rs +++ /dev/null @@ -1,376 +0,0 @@ -// Adapted from https://github.com/rust-lang/rust/blob/1.57.0/compiler/rustc_ast_pretty/src/pp.rs. -// See "Algorithm notes" in the crate-level rustdoc. - -use super::ring::RingBuffer; -use super::{MARGIN, MIN_SPACE}; -use std::borrow::Cow; -use std::cmp; -use std::collections::VecDeque; -use std::iter; - -#[derive(Clone, Copy, PartialEq)] -pub enum Breaks { - Consistent, - Inconsistent, -} - -#[derive(Clone, Copy, Default)] -pub struct BreakToken { - pub offset: isize, - pub blank_space: usize, - pub pre_break: Option, - pub post_break: Option, - pub no_break: Option, - pub if_nonempty: bool, - pub never_break: bool, -} - -#[derive(Clone, Copy)] -pub struct BeginToken { - pub offset: isize, - pub breaks: Breaks, -} - -#[derive(Clone)] -pub enum Token { - String(Cow<'static, str>), - Break(BreakToken), - Begin(BeginToken), - End, -} - -#[derive(Copy, Clone)] -enum PrintFrame { - Fits(Breaks), - Broken(usize, Breaks), -} - -pub const SIZE_INFINITY: isize = 0xffff; - -pub struct Printer { - out: String, - // Number of spaces left on line - space: isize, - // Ring-buffer of tokens and calculated sizes - buf: RingBuffer, - // Total size of tokens already printed - left_total: isize, - // Total size of tokens enqueued, including printed and not yet printed - right_total: isize, - // Holds the ring-buffer index of the Begin that started the current block, - // possibly with the most recent Break after that Begin (if there is any) on - // top of it. Values are pushed and popped on the back of the queue using it - // like stack, and elsewhere old values are popped from the front of the - // queue as they become irrelevant due to the primary ring-buffer advancing. - scan_stack: VecDeque, - // Stack of blocks-in-progress being flushed by print - print_stack: Vec, - // Level of indentation of current line - indent: usize, - // Buffered indentation to avoid writing trailing whitespace - pending_indentation: usize, -} - -#[derive(Clone)] -struct BufEntry { - token: Token, - size: isize, -} - -impl Printer { - pub fn new() -> Self { - Printer { - out: String::new(), - space: MARGIN, - buf: RingBuffer::new(), - left_total: 0, - right_total: 0, - scan_stack: VecDeque::new(), - print_stack: Vec::new(), - indent: 0, - pending_indentation: 0, - } - } - - pub fn eof(mut self) -> String { - if !self.scan_stack.is_empty() { - self.check_stack(0); - self.advance_left(); - } - self.out - } - - pub fn scan_begin(&mut self, token: BeginToken) { - if self.scan_stack.is_empty() { - self.left_total = 1; - self.right_total = 1; - self.buf.clear(); - } - let right = self.buf.push(BufEntry { - token: Token::Begin(token), - size: -self.right_total, - }); - self.scan_stack.push_back(right); - } - - pub fn scan_end(&mut self) { - if self.scan_stack.is_empty() { - self.print_end(); - } else { - if !self.buf.is_empty() { - if let Token::Break(break_token) = self.buf.last().token { - if self.buf.len() >= 2 { - if let Token::Begin(_) = self.buf.second_last().token { - self.buf.pop_last(); - self.buf.pop_last(); - self.scan_stack.pop_back(); - self.scan_stack.pop_back(); - self.right_total -= break_token.blank_space as isize; - return; - } - } - if break_token.if_nonempty { - self.buf.pop_last(); - self.scan_stack.pop_back(); - self.right_total -= break_token.blank_space as isize; - } - } - } - let right = self.buf.push(BufEntry { - token: Token::End, - size: -1, - }); - self.scan_stack.push_back(right); - } - } - - pub fn scan_break(&mut self, token: BreakToken) { - if self.scan_stack.is_empty() { - self.left_total = 1; - self.right_total = 1; - self.buf.clear(); - } else { - self.check_stack(0); - } - let right = self.buf.push(BufEntry { - token: Token::Break(token), - size: -self.right_total, - }); - self.scan_stack.push_back(right); - self.right_total += token.blank_space as isize; - } - - pub fn scan_string(&mut self, string: Cow<'static, str>) { - if self.scan_stack.is_empty() { - self.print_string(string); - } else { - let len = string.len() as isize; - self.buf.push(BufEntry { - token: Token::String(string), - size: len, - }); - self.right_total += len; - self.check_stream(); - } - } - - pub fn offset(&mut self, offset: isize) { - match &mut self.buf.last_mut().token { - Token::Break(token) => token.offset += offset, - Token::Begin(_) => {} - Token::String(_) | Token::End => unreachable!(), - } - } - - pub fn end_with_max_width(&mut self, max: isize) { - let mut depth = 1; - for &index in self.scan_stack.iter().rev() { - let entry = &self.buf[index]; - match entry.token { - Token::Begin(_) => { - depth -= 1; - if depth == 0 { - if entry.size < 0 { - let actual_width = entry.size + self.right_total; - if actual_width > max { - self.buf.push(BufEntry { - token: Token::String(Cow::Borrowed("")), - size: SIZE_INFINITY, - }); - self.right_total += SIZE_INFINITY; - } - } - break; - } - } - Token::End => depth += 1, - Token::Break(_) => {} - Token::String(_) => unreachable!(), - } - } - self.scan_end(); - } - - fn check_stream(&mut self) { - while self.right_total - self.left_total > self.space { - if *self.scan_stack.front().unwrap() == self.buf.index_of_first() { - self.scan_stack.pop_front().unwrap(); - self.buf.first_mut().size = SIZE_INFINITY; - } - - self.advance_left(); - - if self.buf.is_empty() { - break; - } - } - } - - fn advance_left(&mut self) { - while self.buf.first().size >= 0 { - let left = self.buf.pop_first(); - - match left.token { - Token::String(string) => { - self.left_total += left.size; - self.print_string(string); - } - Token::Break(token) => { - self.left_total += token.blank_space as isize; - self.print_break(token, left.size); - } - Token::Begin(token) => self.print_begin(token, left.size), - Token::End => self.print_end(), - } - - if self.buf.is_empty() { - break; - } - } - } - - fn check_stack(&mut self, mut depth: usize) { - while let Some(&index) = self.scan_stack.back() { - let mut entry = &mut self.buf[index]; - match entry.token { - Token::Begin(_) => { - if depth == 0 { - break; - } - self.scan_stack.pop_back().unwrap(); - entry.size += self.right_total; - depth -= 1; - } - Token::End => { - self.scan_stack.pop_back().unwrap(); - entry.size = 1; - depth += 1; - } - Token::Break(_) => { - self.scan_stack.pop_back().unwrap(); - entry.size += self.right_total; - if depth == 0 { - break; - } - } - Token::String(_) => unreachable!(), - } - } - } - - fn get_top(&self) -> PrintFrame { - const OUTER: PrintFrame = PrintFrame::Broken(0, Breaks::Inconsistent); - self.print_stack.last().map_or(OUTER, PrintFrame::clone) - } - - fn print_begin(&mut self, token: BeginToken, size: isize) { - if cfg!(prettyplease_debug) { - self.out.push(match token.breaks { - Breaks::Consistent => '«', - Breaks::Inconsistent => '‹', - }); - if cfg!(prettyplease_debug_indent) { - self.out - .extend(token.offset.to_string().chars().map(|ch| match ch { - '0'..='9' => ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉'] - [(ch as u8 - b'0') as usize] - as char, - '-' => '₋', - _ => unreachable!(), - })); - } - } - if size > self.space { - self.print_stack - .push(PrintFrame::Broken(self.indent, token.breaks)); - self.indent = usize::try_from(self.indent as isize + token.offset).unwrap(); - } else { - self.print_stack.push(PrintFrame::Fits(token.breaks)); - } - } - - fn print_end(&mut self) { - let breaks = match self.print_stack.pop().unwrap() { - PrintFrame::Broken(indent, breaks) => { - self.indent = indent; - breaks - } - PrintFrame::Fits(breaks) => breaks, - }; - if cfg!(prettyplease_debug) { - self.out.push(match breaks { - Breaks::Consistent => '»', - Breaks::Inconsistent => '›', - }); - } - } - - fn print_break(&mut self, token: BreakToken, size: isize) { - let fits = token.never_break - || match self.get_top() { - PrintFrame::Fits(..) => true, - PrintFrame::Broken(.., Breaks::Consistent) => false, - PrintFrame::Broken(.., Breaks::Inconsistent) => size <= self.space, - }; - if fits { - self.pending_indentation += token.blank_space; - self.space -= token.blank_space as isize; - if let Some(no_break) = token.no_break { - self.out.push(no_break); - self.space -= no_break.len_utf8() as isize; - } - if cfg!(prettyplease_debug) { - self.out.push('·'); - } - } else { - if let Some(pre_break) = token.pre_break { - self.out.push(pre_break); - } - if cfg!(prettyplease_debug) { - self.out.push('·'); - } - self.out.push('\n'); - let indent = self.indent as isize + token.offset; - self.pending_indentation = usize::try_from(indent).unwrap(); - self.space = cmp::max(MARGIN - indent, MIN_SPACE); - if let Some(post_break) = token.post_break { - self.print_indent(); - self.out.push(post_break); - self.space -= post_break.len_utf8() as isize; - } - } - } - - fn print_string(&mut self, string: Cow<'static, str>) { - self.print_indent(); - self.out.push_str(&string); - self.space -= string.len() as isize; - } - - fn print_indent(&mut self) { - self.out.reserve(self.pending_indentation); - self.out - .extend(iter::repeat(' ').take(self.pending_indentation)); - self.pending_indentation = 0; - } -} diff --git a/packages/autofmt/src/prettyplease/attr.rs b/packages/autofmt/src/prettyplease/attr.rs deleted file mode 100644 index d934a1c1f..000000000 --- a/packages/autofmt/src/prettyplease/attr.rs +++ /dev/null @@ -1,208 +0,0 @@ -use super::algorithm::Printer; -use super::INDENT; -use proc_macro2::{Delimiter, TokenStream, TokenTree}; -use syn::{AttrStyle, Attribute, Lit, PathArguments}; - -impl Printer { - pub fn outer_attrs(&mut self, attrs: &[Attribute]) { - for attr in attrs { - if let AttrStyle::Outer = attr.style { - self.attr(attr); - } - } - } - - pub fn inner_attrs(&mut self, attrs: &[Attribute]) { - for attr in attrs { - if let AttrStyle::Inner(_) = attr.style { - self.attr(attr); - } - } - } - - fn attr(&mut self, attr: &Attribute) { - if let Some(doc) = value_of_attribute("doc", attr) { - if doc.contains('\n') { - self.word(match attr.style { - AttrStyle::Outer => "/**", - AttrStyle::Inner(_) => "/*!", - }); - self.word(doc); - self.word("*/"); - } else { - self.word(match attr.style { - AttrStyle::Outer => "///", - AttrStyle::Inner(_) => "//!", - }); - self.word(doc); - } - self.hardbreak(); - } else if let Some(comment) = value_of_attribute("comment", attr) { - if comment.contains('\n') { - self.word("/*"); - self.word(comment); - self.word("*/"); - } else { - self.word("//"); - self.word(comment); - } - self.hardbreak(); - } else { - self.word(match attr.style { - AttrStyle::Outer => "#", - AttrStyle::Inner(_) => "#!", - }); - self.word("["); - self.path(&attr.path); - self.attr_tokens(attr.tokens.clone()); - self.word("]"); - self.space(); - } - } - - fn attr_tokens(&mut self, tokens: TokenStream) { - let mut stack = Vec::new(); - stack.push((tokens.into_iter().peekable(), Delimiter::None)); - let mut space = Self::nbsp as fn(&mut Self); - - #[derive(PartialEq)] - enum State { - Word, - Punct, - TrailingComma, - } - - use State::*; - let mut state = Word; - - while let Some((tokens, delimiter)) = stack.last_mut() { - match tokens.next() { - Some(TokenTree::Ident(ident)) => { - if let Word = state { - space(self); - } - self.ident(&ident); - state = Word; - } - Some(TokenTree::Punct(punct)) => { - let ch = punct.as_char(); - if let (Word, '=') = (state, ch) { - self.nbsp(); - } - if ch == ',' && tokens.peek().is_none() { - self.trailing_comma(true); - state = TrailingComma; - } else { - self.token_punct(ch); - if ch == '=' { - self.nbsp(); - } else if ch == ',' { - space(self); - } - state = Punct; - } - } - Some(TokenTree::Literal(literal)) => { - if let Word = state { - space(self); - } - self.token_literal(&literal); - state = Word; - } - Some(TokenTree::Group(group)) => { - let delimiter = group.delimiter(); - let stream = group.stream(); - match delimiter { - Delimiter::Parenthesis => { - self.word("("); - self.cbox(INDENT); - self.zerobreak(); - state = Punct; - } - Delimiter::Brace => { - self.word("{"); - state = Punct; - } - Delimiter::Bracket => { - self.word("["); - state = Punct; - } - Delimiter::None => {} - } - stack.push((stream.into_iter().peekable(), delimiter)); - space = Self::space; - } - None => { - match delimiter { - Delimiter::Parenthesis => { - if state != TrailingComma { - self.zerobreak(); - } - self.offset(-INDENT); - self.end(); - self.word(")"); - state = Punct; - } - Delimiter::Brace => { - self.word("}"); - state = Punct; - } - Delimiter::Bracket => { - self.word("]"); - state = Punct; - } - Delimiter::None => {} - } - stack.pop(); - if stack.is_empty() { - space = Self::nbsp; - } - } - } - } - } -} - -fn value_of_attribute(requested: &str, attr: &Attribute) -> Option { - let is_doc = attr.path.leading_colon.is_none() - && attr.path.segments.len() == 1 - && matches!(attr.path.segments[0].arguments, PathArguments::None) - && attr.path.segments[0].ident == requested; - if !is_doc { - return None; - } - let mut tokens = attr.tokens.clone().into_iter(); - match tokens.next() { - Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {} - _ => return None, - } - let literal = match tokens.next() { - Some(TokenTree::Literal(literal)) => literal, - _ => return None, - }; - if tokens.next().is_some() { - return None; - } - match Lit::new(literal) { - Lit::Str(string) => Some(string.value()), - _ => None, - } -} - -pub fn has_outer(attrs: &[Attribute]) -> bool { - for attr in attrs { - if let AttrStyle::Outer = attr.style { - return true; - } - } - false -} - -pub fn has_inner(attrs: &[Attribute]) -> bool { - for attr in attrs { - if let AttrStyle::Inner(_) = attr.style { - return true; - } - } - false -} diff --git a/packages/autofmt/src/prettyplease/convenience.rs b/packages/autofmt/src/prettyplease/convenience.rs deleted file mode 100644 index f87206320..000000000 --- a/packages/autofmt/src/prettyplease/convenience.rs +++ /dev/null @@ -1,98 +0,0 @@ -use super::algorithm::{self, BeginToken, BreakToken, Breaks, Printer}; -use std::borrow::Cow; - -impl Printer { - pub fn ibox(&mut self, indent: isize) { - self.scan_begin(BeginToken { - offset: indent, - breaks: Breaks::Inconsistent, - }); - } - - pub fn cbox(&mut self, indent: isize) { - self.scan_begin(BeginToken { - offset: indent, - breaks: Breaks::Consistent, - }); - } - - pub fn end(&mut self) { - self.scan_end(); - } - - pub fn word>>(&mut self, wrd: S) { - let s = wrd.into(); - self.scan_string(s); - } - - fn spaces(&mut self, n: usize) { - self.scan_break(BreakToken { - blank_space: n, - ..BreakToken::default() - }); - } - - pub fn zerobreak(&mut self) { - self.spaces(0); - } - - pub fn space(&mut self) { - self.spaces(1); - } - - pub fn nbsp(&mut self) { - self.word(" "); - } - - pub fn hardbreak(&mut self) { - self.spaces(algorithm::SIZE_INFINITY as usize); - } - - pub fn space_if_nonempty(&mut self) { - self.scan_break(BreakToken { - blank_space: 1, - if_nonempty: true, - ..BreakToken::default() - }); - } - - pub fn hardbreak_if_nonempty(&mut self) { - self.scan_break(BreakToken { - blank_space: algorithm::SIZE_INFINITY as usize, - if_nonempty: true, - ..BreakToken::default() - }); - } - - pub fn trailing_comma(&mut self, is_last: bool) { - if is_last { - self.scan_break(BreakToken { - pre_break: Some(','), - ..BreakToken::default() - }); - } else { - self.word(","); - self.space(); - } - } - - pub fn trailing_comma_or_space(&mut self, is_last: bool) { - if is_last { - self.scan_break(BreakToken { - blank_space: 1, - pre_break: Some(','), - ..BreakToken::default() - }); - } else { - self.word(","); - self.space(); - } - } - - pub fn neverbreak(&mut self) { - self.scan_break(BreakToken { - never_break: true, - ..BreakToken::default() - }); - } -} diff --git a/packages/autofmt/src/prettyplease/data.rs b/packages/autofmt/src/prettyplease/data.rs deleted file mode 100644 index be20eae05..000000000 --- a/packages/autofmt/src/prettyplease/data.rs +++ /dev/null @@ -1,95 +0,0 @@ -use super::algorithm::Printer; -use super::iter::IterDelimited; -use super::INDENT; -use syn::{ - Field, Fields, FieldsUnnamed, PathArguments, Variant, VisCrate, VisPublic, VisRestricted, - Visibility, -}; - -impl Printer { - pub fn variant(&mut self, variant: &Variant) { - self.outer_attrs(&variant.attrs); - self.ident(&variant.ident); - match &variant.fields { - Fields::Named(fields) => { - self.nbsp(); - self.word("{"); - self.cbox(INDENT); - self.space(); - for field in fields.named.iter().delimited() { - self.field(&field); - self.trailing_comma_or_space(field.is_last); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } - Fields::Unnamed(fields) => { - self.cbox(INDENT); - self.fields_unnamed(fields); - self.end(); - } - Fields::Unit => {} - } - if let Some((_eq_token, discriminant)) = &variant.discriminant { - self.word(" = "); - self.expr(discriminant); - } - } - - pub fn fields_unnamed(&mut self, fields: &FieldsUnnamed) { - self.word("("); - self.zerobreak(); - for field in fields.unnamed.iter().delimited() { - self.field(&field); - self.trailing_comma(field.is_last); - } - self.offset(-INDENT); - self.word(")"); - } - - pub fn field(&mut self, field: &Field) { - self.outer_attrs(&field.attrs); - self.visibility(&field.vis); - if let Some(ident) = &field.ident { - self.ident(ident); - self.word(": "); - } - self.ty(&field.ty); - } - - pub fn visibility(&mut self, vis: &Visibility) { - match vis { - Visibility::Public(vis) => self.vis_public(vis), - Visibility::Crate(vis) => self.vis_crate(vis), - Visibility::Restricted(vis) => self.vis_restricted(vis), - Visibility::Inherited => {} - } - } - - fn vis_public(&mut self, vis: &VisPublic) { - let _ = vis; - self.word("pub "); - } - - fn vis_crate(&mut self, vis: &VisCrate) { - let _ = vis; - self.word("crate "); - } - - fn vis_restricted(&mut self, vis: &VisRestricted) { - self.word("pub("); - let omit_in = vis.path.leading_colon.is_none() - && vis.path.segments.len() == 1 - && matches!(vis.path.segments[0].arguments, PathArguments::None) - && matches!( - vis.path.segments[0].ident.to_string().as_str(), - "self" | "super" | "crate", - ); - if !omit_in { - self.word("in "); - } - self.path(&vis.path); - self.word(") "); - } -} diff --git a/packages/autofmt/src/prettyplease/expr.rs b/packages/autofmt/src/prettyplease/expr.rs deleted file mode 100644 index e659118a4..000000000 --- a/packages/autofmt/src/prettyplease/expr.rs +++ /dev/null @@ -1,1028 +0,0 @@ -use super::algorithm::{BreakToken, Printer}; -use super::attr; -use super::iter::IterDelimited; -use super::stmt; -use super::INDENT; -use proc_macro2::TokenStream; -use syn::punctuated::Punctuated; -use syn::{ - token, Arm, Attribute, BinOp, Block, Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, - ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, - ExprContinue, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLit, ExprLoop, - ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, - ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, - ExprUnsafe, ExprWhile, ExprYield, FieldValue, GenericMethodArgument, Index, Label, Member, - MethodTurbofish, PathArguments, RangeLimits, ReturnType, Stmt, Token, UnOp, -}; - -impl Printer { - pub fn expr(&mut self, expr: &Expr) { - match expr { - Expr::Array(expr) => self.expr_array(expr), - Expr::Assign(expr) => self.expr_assign(expr), - Expr::AssignOp(expr) => self.expr_assign_op(expr), - Expr::Async(expr) => self.expr_async(expr), - Expr::Await(expr) => self.expr_await(expr, false), - Expr::Binary(expr) => self.expr_binary(expr), - Expr::Block(expr) => self.expr_block(expr), - Expr::Box(expr) => self.expr_box(expr), - Expr::Break(expr) => self.expr_break(expr), - Expr::Call(expr) => self.expr_call(expr, false), - Expr::Cast(expr) => self.expr_cast(expr), - Expr::Closure(expr) => self.expr_closure(expr), - Expr::Continue(expr) => self.expr_continue(expr), - Expr::Field(expr) => self.expr_field(expr, false), - Expr::ForLoop(expr) => self.expr_for_loop(expr), - Expr::Group(expr) => self.expr_group(expr), - Expr::If(expr) => self.expr_if(expr), - Expr::Index(expr) => self.expr_index(expr, false), - Expr::Let(expr) => self.expr_let(expr), - Expr::Lit(expr) => self.expr_lit(expr), - Expr::Loop(expr) => self.expr_loop(expr), - Expr::Macro(expr) => self.expr_macro(expr), - Expr::Match(expr) => self.expr_match(expr), - Expr::MethodCall(expr) => self.expr_method_call(expr, false), - Expr::Paren(expr) => self.expr_paren(expr), - Expr::Path(expr) => self.expr_path(expr), - Expr::Range(expr) => self.expr_range(expr), - Expr::Reference(expr) => self.expr_reference(expr), - Expr::Repeat(expr) => self.expr_repeat(expr), - Expr::Return(expr) => self.expr_return(expr), - Expr::Struct(expr) => self.expr_struct(expr), - Expr::Try(expr) => self.expr_try(expr, false), - Expr::TryBlock(expr) => self.expr_try_block(expr), - Expr::Tuple(expr) => self.expr_tuple(expr), - Expr::Type(expr) => self.expr_type(expr), - Expr::Unary(expr) => self.expr_unary(expr), - Expr::Unsafe(expr) => self.expr_unsafe(expr), - Expr::Verbatim(expr) => self.expr_verbatim(expr), - Expr::While(expr) => self.expr_while(expr), - Expr::Yield(expr) => self.expr_yield(expr), - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => unimplemented!("unknown Expr"), - } - } - - pub fn expr_beginning_of_line(&mut self, expr: &Expr, beginning_of_line: bool) { - match expr { - Expr::Await(expr) => self.expr_await(expr, beginning_of_line), - Expr::Field(expr) => self.expr_field(expr, beginning_of_line), - Expr::Index(expr) => self.expr_index(expr, beginning_of_line), - Expr::MethodCall(expr) => self.expr_method_call(expr, beginning_of_line), - Expr::Try(expr) => self.expr_try(expr, beginning_of_line), - _ => self.expr(expr), - } - } - - fn subexpr(&mut self, expr: &Expr, beginning_of_line: bool) { - match expr { - Expr::Await(expr) => self.subexpr_await(expr, beginning_of_line), - Expr::Call(expr) => self.subexpr_call(expr), - Expr::Field(expr) => self.subexpr_field(expr, beginning_of_line), - Expr::Index(expr) => self.subexpr_index(expr, beginning_of_line), - Expr::MethodCall(expr) => self.subexpr_method_call(expr, beginning_of_line, false), - Expr::Try(expr) => self.subexpr_try(expr, beginning_of_line), - _ => { - self.cbox(-INDENT); - self.expr(expr); - self.end(); - } - } - } - - // If the given expression is a bare `ExprStruct`, wraps it in parenthesis - // before appending it to `TokenStream`. - fn wrap_exterior_struct(&mut self, expr: &Expr) { - let needs_paren = contains_exterior_struct_lit(expr); - if needs_paren { - self.word("("); - } - self.cbox(0); - self.expr(expr); - if needs_paren { - self.word(")"); - } - if needs_newline_if_wrap(expr) { - self.space(); - } else { - self.nbsp(); - } - self.end(); - } - - fn expr_array(&mut self, expr: &ExprArray) { - self.outer_attrs(&expr.attrs); - self.word("["); - self.cbox(INDENT); - self.zerobreak(); - for element in expr.elems.iter().delimited() { - self.expr(&element); - self.trailing_comma(element.is_last); - } - self.offset(-INDENT); - self.end(); - self.word("]"); - } - - fn expr_assign(&mut self, expr: &ExprAssign) { - self.outer_attrs(&expr.attrs); - self.ibox(0); - self.expr(&expr.left); - self.word(" = "); - self.expr(&expr.right); - self.end(); - } - - fn expr_assign_op(&mut self, expr: &ExprAssignOp) { - self.outer_attrs(&expr.attrs); - self.ibox(INDENT); - self.ibox(-INDENT); - self.expr(&expr.left); - self.end(); - self.space(); - self.binary_operator(&expr.op); - self.nbsp(); - self.expr(&expr.right); - self.end(); - } - - fn expr_async(&mut self, expr: &ExprAsync) { - self.outer_attrs(&expr.attrs); - self.word("async "); - if expr.capture.is_some() { - self.word("move "); - } - self.cbox(INDENT); - self.small_block(&expr.block, &expr.attrs); - self.end(); - } - - fn expr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool) { - self.outer_attrs(&expr.attrs); - self.cbox(INDENT); - self.subexpr_await(expr, beginning_of_line); - self.end(); - } - - fn subexpr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool) { - self.subexpr(&expr.base, beginning_of_line); - self.zerobreak_unless_short_ident(beginning_of_line, &expr.base); - self.word(".await"); - } - - fn expr_binary(&mut self, expr: &ExprBinary) { - self.outer_attrs(&expr.attrs); - self.ibox(INDENT); - self.ibox(-INDENT); - self.expr(&expr.left); - self.end(); - self.space(); - self.binary_operator(&expr.op); - self.nbsp(); - self.expr(&expr.right); - self.end(); - } - - pub fn expr_block(&mut self, expr: &ExprBlock) { - self.outer_attrs(&expr.attrs); - if let Some(label) = &expr.label { - self.label(label); - } - self.cbox(INDENT); - self.small_block(&expr.block, &expr.attrs); - self.end(); - } - - fn expr_box(&mut self, expr: &ExprBox) { - self.outer_attrs(&expr.attrs); - self.word("box "); - self.expr(&expr.expr); - } - - fn expr_break(&mut self, expr: &ExprBreak) { - self.outer_attrs(&expr.attrs); - self.word("break"); - if let Some(lifetime) = &expr.label { - self.nbsp(); - self.lifetime(lifetime); - } - if let Some(value) = &expr.expr { - self.nbsp(); - self.expr(value); - } - } - - fn expr_call(&mut self, expr: &ExprCall, beginning_of_line: bool) { - self.outer_attrs(&expr.attrs); - self.expr_beginning_of_line(&expr.func, beginning_of_line); - self.call_args(&expr.args); - } - - fn subexpr_call(&mut self, expr: &ExprCall) { - self.subexpr(&expr.func, false); - self.call_args(&expr.args); - } - - fn expr_cast(&mut self, expr: &ExprCast) { - self.outer_attrs(&expr.attrs); - self.ibox(INDENT); - self.ibox(-INDENT); - self.expr(&expr.expr); - self.end(); - self.space(); - self.word("as "); - self.ty(&expr.ty); - self.end(); - } - - fn expr_closure(&mut self, expr: &ExprClosure) { - self.outer_attrs(&expr.attrs); - self.ibox(0); - if expr.asyncness.is_some() { - self.word("async "); - } - if expr.movability.is_some() { - self.word("static "); - } - if expr.capture.is_some() { - self.word("move "); - } - self.cbox(INDENT); - self.word("|"); - for pat in expr.inputs.iter().delimited() { - if pat.is_first { - self.zerobreak(); - } - self.pat(&pat); - if !pat.is_last { - self.word(","); - self.space(); - } - } - match &expr.output { - ReturnType::Default => { - self.word("|"); - self.space(); - self.offset(-INDENT); - self.end(); - } - ReturnType::Type(_arrow, ty) => { - if !expr.inputs.is_empty() { - self.trailing_comma(true); - self.offset(-INDENT); - } - self.word("|"); - self.end(); - self.word(" -> "); - self.ty(ty); - self.nbsp(); - } - } - self.neverbreak(); - self.expr(&expr.body); - self.end(); - } - - fn expr_continue(&mut self, expr: &ExprContinue) { - self.outer_attrs(&expr.attrs); - self.word("continue"); - if let Some(lifetime) = &expr.label { - self.nbsp(); - self.lifetime(lifetime); - } - } - - fn expr_field(&mut self, expr: &ExprField, beginning_of_line: bool) { - self.outer_attrs(&expr.attrs); - self.cbox(INDENT); - self.subexpr_field(expr, beginning_of_line); - self.end(); - } - - fn subexpr_field(&mut self, expr: &ExprField, beginning_of_line: bool) { - self.subexpr(&expr.base, beginning_of_line); - self.zerobreak_unless_short_ident(beginning_of_line, &expr.base); - self.word("."); - self.member(&expr.member); - } - - fn expr_for_loop(&mut self, expr: &ExprForLoop) { - self.outer_attrs(&expr.attrs); - self.ibox(0); - if let Some(label) = &expr.label { - self.label(label); - } - self.word("for "); - self.pat(&expr.pat); - self.word(" in "); - self.neverbreak(); - self.wrap_exterior_struct(&expr.expr); - self.word("{"); - self.neverbreak(); - self.cbox(INDENT); - self.hardbreak_if_nonempty(); - self.inner_attrs(&expr.attrs); - for stmt in &expr.body.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.end(); - } - - fn expr_group(&mut self, expr: &ExprGroup) { - self.outer_attrs(&expr.attrs); - self.expr(&expr.expr); - } - - fn expr_if(&mut self, expr: &ExprIf) { - self.outer_attrs(&expr.attrs); - self.cbox(INDENT); - self.word("if "); - self.cbox(-INDENT); - self.wrap_exterior_struct(&expr.cond); - self.end(); - if let Some((_else_token, else_branch)) = &expr.else_branch { - let mut else_branch = &**else_branch; - self.small_block(&expr.then_branch, &[]); - loop { - self.word(" else "); - match else_branch { - Expr::If(expr) => { - self.word("if "); - self.wrap_exterior_struct(&expr.cond); - self.small_block(&expr.then_branch, &[]); - if let Some((_else_token, next)) = &expr.else_branch { - else_branch = next; - continue; - } - } - Expr::Block(expr) => { - self.small_block(&expr.block, &[]); - } - // If not one of the valid expressions to exist in an else - // clause, wrap in a block. - other => { - self.word("{"); - self.space(); - self.ibox(INDENT); - self.expr(other); - self.end(); - self.space(); - self.offset(-INDENT); - self.word("}"); - } - } - break; - } - } else if expr.then_branch.stmts.is_empty() { - self.word("{}"); - } else { - self.word("{"); - self.hardbreak(); - for stmt in &expr.then_branch.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.word("}"); - } - self.end(); - } - - fn expr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) { - self.outer_attrs(&expr.attrs); - self.expr_beginning_of_line(&expr.expr, beginning_of_line); - self.word("["); - self.expr(&expr.index); - self.word("]"); - } - - fn subexpr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) { - self.subexpr(&expr.expr, beginning_of_line); - self.word("["); - self.expr(&expr.index); - self.word("]"); - } - - fn expr_let(&mut self, expr: &ExprLet) { - self.outer_attrs(&expr.attrs); - self.ibox(INDENT); - self.word("let "); - self.ibox(-INDENT); - self.pat(&expr.pat); - self.end(); - self.space(); - self.word("= "); - let needs_paren = contains_exterior_struct_lit(&expr.expr); - if needs_paren { - self.word("("); - } - self.expr(&expr.expr); - if needs_paren { - self.word(")"); - } - self.end(); - } - - pub fn expr_lit(&mut self, expr: &ExprLit) { - self.outer_attrs(&expr.attrs); - self.lit(&expr.lit); - } - - fn expr_loop(&mut self, expr: &ExprLoop) { - self.outer_attrs(&expr.attrs); - if let Some(label) = &expr.label { - self.label(label); - } - self.word("loop {"); - self.cbox(INDENT); - self.hardbreak_if_nonempty(); - self.inner_attrs(&expr.attrs); - for stmt in &expr.body.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } - - fn expr_macro(&mut self, expr: &ExprMacro) { - self.outer_attrs(&expr.attrs); - self.mac(&expr.mac, None); - } - - fn expr_match(&mut self, expr: &ExprMatch) { - self.outer_attrs(&expr.attrs); - self.ibox(0); - self.word("match "); - self.wrap_exterior_struct(&expr.expr); - self.word("{"); - self.neverbreak(); - self.cbox(INDENT); - self.hardbreak_if_nonempty(); - self.inner_attrs(&expr.attrs); - for arm in &expr.arms { - self.arm(arm); - self.hardbreak(); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.end(); - } - - fn expr_method_call(&mut self, expr: &ExprMethodCall, beginning_of_line: bool) { - self.outer_attrs(&expr.attrs); - self.cbox(INDENT); - let unindent_call_args = beginning_of_line && is_short_ident(&expr.receiver); - self.subexpr_method_call(expr, beginning_of_line, unindent_call_args); - self.end(); - } - - fn subexpr_method_call( - &mut self, - expr: &ExprMethodCall, - beginning_of_line: bool, - unindent_call_args: bool, - ) { - self.subexpr(&expr.receiver, beginning_of_line); - self.zerobreak_unless_short_ident(beginning_of_line, &expr.receiver); - self.word("."); - self.ident(&expr.method); - if let Some(turbofish) = &expr.turbofish { - self.method_turbofish(turbofish); - } - self.cbox(if unindent_call_args { -INDENT } else { 0 }); - self.call_args(&expr.args); - self.end(); - } - - fn expr_paren(&mut self, expr: &ExprParen) { - self.outer_attrs(&expr.attrs); - self.word("("); - self.expr(&expr.expr); - self.word(")"); - } - - fn expr_path(&mut self, expr: &ExprPath) { - self.outer_attrs(&expr.attrs); - self.qpath(&expr.qself, &expr.path); - } - - fn expr_range(&mut self, expr: &ExprRange) { - self.outer_attrs(&expr.attrs); - if let Some(from) = &expr.from { - self.expr(from); - } - self.word(match expr.limits { - RangeLimits::HalfOpen(_) => "..", - RangeLimits::Closed(_) => "..=", - }); - if let Some(to) = &expr.to { - self.expr(to); - } - } - - fn expr_reference(&mut self, expr: &ExprReference) { - self.outer_attrs(&expr.attrs); - self.word("&"); - if expr.mutability.is_some() { - self.word("mut "); - } - self.expr(&expr.expr); - } - - fn expr_repeat(&mut self, expr: &ExprRepeat) { - self.outer_attrs(&expr.attrs); - self.word("["); - self.expr(&expr.expr); - self.word("; "); - self.expr(&expr.len); - self.word("]"); - } - - fn expr_return(&mut self, expr: &ExprReturn) { - self.outer_attrs(&expr.attrs); - self.word("return"); - if let Some(value) = &expr.expr { - self.nbsp(); - self.expr(value); - } - } - - fn expr_struct(&mut self, expr: &ExprStruct) { - self.outer_attrs(&expr.attrs); - self.cbox(INDENT); - self.ibox(-INDENT); - self.path(&expr.path); - self.end(); - self.word(" {"); - self.space_if_nonempty(); - for field_value in expr.fields.iter().delimited() { - self.field_value(&field_value); - self.trailing_comma_or_space(field_value.is_last && expr.rest.is_none()); - } - if let Some(rest) = &expr.rest { - self.word(".."); - self.expr(rest); - self.space(); - } - self.offset(-INDENT); - self.end_with_max_width(34); - self.word("}"); - } - - fn expr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) { - self.outer_attrs(&expr.attrs); - self.expr_beginning_of_line(&expr.expr, beginning_of_line); - self.word("?"); - } - - fn subexpr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) { - self.subexpr(&expr.expr, beginning_of_line); - self.word("?"); - } - - fn expr_try_block(&mut self, expr: &ExprTryBlock) { - self.outer_attrs(&expr.attrs); - self.word("try "); - self.cbox(INDENT); - self.small_block(&expr.block, &expr.attrs); - self.end(); - } - - fn expr_tuple(&mut self, expr: &ExprTuple) { - self.outer_attrs(&expr.attrs); - self.word("("); - self.cbox(INDENT); - self.zerobreak(); - for elem in expr.elems.iter().delimited() { - self.expr(&elem); - if expr.elems.len() == 1 { - self.word(","); - self.zerobreak(); - } else { - self.trailing_comma(elem.is_last); - } - } - self.offset(-INDENT); - self.end(); - self.word(")"); - } - - fn expr_type(&mut self, expr: &ExprType) { - self.outer_attrs(&expr.attrs); - self.ibox(INDENT); - self.ibox(-INDENT); - self.expr(&expr.expr); - self.end(); - self.space(); - self.word(": "); - self.ty(&expr.ty); - self.end(); - } - - fn expr_unary(&mut self, expr: &ExprUnary) { - self.outer_attrs(&expr.attrs); - self.unary_operator(&expr.op); - self.expr(&expr.expr); - } - - fn expr_unsafe(&mut self, expr: &ExprUnsafe) { - self.outer_attrs(&expr.attrs); - self.word("unsafe {"); - self.cbox(INDENT); - self.space_if_nonempty(); - self.inner_attrs(&expr.attrs); - for stmt in expr.block.stmts.iter().delimited() { - if stmt.is_first && stmt.is_last { - if let Stmt::Expr(expr) = &*stmt { - self.expr(expr); - self.space(); - continue; - } - } - self.stmt(&stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } - - fn expr_verbatim(&mut self, expr: &TokenStream) { - if !expr.is_empty() { - unimplemented!("Expr::Verbatim `{}`", expr); - } - } - - fn expr_while(&mut self, expr: &ExprWhile) { - self.outer_attrs(&expr.attrs); - if let Some(label) = &expr.label { - self.label(label); - } - self.word("while "); - self.wrap_exterior_struct(&expr.cond); - self.word("{"); - self.neverbreak(); - self.cbox(INDENT); - self.hardbreak_if_nonempty(); - self.inner_attrs(&expr.attrs); - for stmt in &expr.body.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } - - fn expr_yield(&mut self, expr: &ExprYield) { - self.outer_attrs(&expr.attrs); - self.word("yield"); - if let Some(value) = &expr.expr { - self.nbsp(); - self.expr(value); - } - } - - fn label(&mut self, label: &Label) { - self.lifetime(&label.name); - self.word(": "); - } - - fn field_value(&mut self, field_value: &FieldValue) { - self.outer_attrs(&field_value.attrs); - self.member(&field_value.member); - if field_value.colon_token.is_some() { - self.word(": "); - self.ibox(0); - self.expr(&field_value.expr); - self.end(); - } - } - - fn arm(&mut self, arm: &Arm) { - self.outer_attrs(&arm.attrs); - self.ibox(0); - self.pat(&arm.pat); - if let Some((_if_token, guard)) = &arm.guard { - self.word(" if "); - self.expr(guard); - } - self.word(" =>"); - let empty_block; - let mut body = &*arm.body; - while let Expr::Block(expr) = body { - if expr.attrs.is_empty() && expr.label.is_none() { - let mut stmts = expr.block.stmts.iter(); - if let (Some(Stmt::Expr(inner)), None) = (stmts.next(), stmts.next()) { - body = inner; - continue; - } - } - break; - } - if let Expr::Tuple(expr) = body { - if expr.elems.is_empty() && expr.attrs.is_empty() { - empty_block = Expr::Block(ExprBlock { - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace::default(), - stmts: Vec::new(), - }, - }); - body = &empty_block; - } - } - if let Expr::Block(body) = body { - self.nbsp(); - if let Some(label) = &body.label { - self.label(label); - } - self.word("{"); - self.neverbreak(); - self.cbox(INDENT); - self.hardbreak_if_nonempty(); - self.inner_attrs(&body.attrs); - for stmt in &body.block.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.end(); - } else { - self.nbsp(); - self.neverbreak(); - self.cbox(INDENT); - self.scan_break(BreakToken { - pre_break: Some('{'), - ..BreakToken::default() - }); - self.expr(body); - self.scan_break(BreakToken { - offset: -INDENT, - pre_break: stmt::add_semi(body).then(|| ';'), - post_break: Some('}'), - no_break: requires_terminator(body).then(|| ','), - ..BreakToken::default() - }); - self.end(); - self.end(); - } - } - - fn method_turbofish(&mut self, turbofish: &MethodTurbofish) { - self.word("::<"); - self.cbox(0); - self.zerobreak(); - for arg in turbofish.args.iter().delimited() { - self.generic_method_argument(&arg); - self.trailing_comma(arg.is_last); - } - self.offset(-INDENT); - self.end(); - self.word(">"); - } - - fn generic_method_argument(&mut self, generic: &GenericMethodArgument) { - match generic { - GenericMethodArgument::Type(arg) => self.ty(arg), - GenericMethodArgument::Const(arg) => self.expr(arg), - } - } - - fn call_args(&mut self, args: &Punctuated) { - self.word("("); - let mut iter = args.iter(); - match (iter.next(), iter.next()) { - ( - Some( - expr @ (Expr::Array(ExprArray { attrs, .. }) - | Expr::Async(ExprAsync { attrs, .. }) - | Expr::Block(ExprBlock { attrs, .. }) - | Expr::Closure(ExprClosure { attrs, .. }) - | Expr::Struct(ExprStruct { attrs, .. }) - | Expr::TryBlock(ExprTryBlock { attrs, .. }) - | Expr::Tuple(ExprTuple { attrs, .. }) - | Expr::Unsafe(ExprUnsafe { attrs, .. })), - ), - None, - ) if !attr::has_outer(attrs) => { - self.expr(expr); - } - _ => { - self.cbox(INDENT); - self.zerobreak(); - for arg in args.iter().delimited() { - self.expr(&arg); - self.trailing_comma(arg.is_last); - } - self.offset(-INDENT); - self.end(); - } - } - self.word(")"); - } - - fn small_block(&mut self, block: &Block, attrs: &[Attribute]) { - self.word("{"); - if attr::has_inner(attrs) || !block.stmts.is_empty() { - self.space(); - self.inner_attrs(attrs); - match (block.stmts.get(0), block.stmts.get(1)) { - (Some(Stmt::Expr(expr)), None) if stmt::break_after(expr) => { - self.ibox(0); - self.expr_beginning_of_line(expr, true); - self.end(); - self.space(); - } - _ => { - for stmt in &block.stmts { - self.stmt(stmt); - } - } - } - self.offset(-INDENT); - } - self.word("}"); - } - - pub fn member(&mut self, member: &Member) { - match member { - Member::Named(ident) => self.ident(ident), - Member::Unnamed(index) => self.index(index), - } - } - - fn index(&mut self, member: &Index) { - self.word(member.index.to_string()); - } - - fn binary_operator(&mut self, op: &BinOp) { - self.word(match op { - BinOp::Add(_) => "+", - BinOp::Sub(_) => "-", - BinOp::Mul(_) => "*", - BinOp::Div(_) => "/", - BinOp::Rem(_) => "%", - BinOp::And(_) => "&&", - BinOp::Or(_) => "||", - BinOp::BitXor(_) => "^", - BinOp::BitAnd(_) => "&", - BinOp::BitOr(_) => "|", - BinOp::Shl(_) => "<<", - BinOp::Shr(_) => ">>", - BinOp::Eq(_) => "==", - BinOp::Lt(_) => "<", - BinOp::Le(_) => "<=", - BinOp::Ne(_) => "!=", - BinOp::Ge(_) => ">=", - BinOp::Gt(_) => ">", - BinOp::AddEq(_) => "+=", - BinOp::SubEq(_) => "-=", - BinOp::MulEq(_) => "*=", - BinOp::DivEq(_) => "/=", - BinOp::RemEq(_) => "%=", - BinOp::BitXorEq(_) => "^=", - BinOp::BitAndEq(_) => "&=", - BinOp::BitOrEq(_) => "|=", - BinOp::ShlEq(_) => "<<=", - BinOp::ShrEq(_) => ">>=", - }); - } - - fn unary_operator(&mut self, op: &UnOp) { - self.word(match op { - UnOp::Deref(_) => "*", - UnOp::Not(_) => "!", - UnOp::Neg(_) => "-", - }); - } - - fn zerobreak_unless_short_ident(&mut self, beginning_of_line: bool, expr: &Expr) { - if beginning_of_line && is_short_ident(expr) { - return; - } - self.zerobreak(); - } -} - -pub fn requires_terminator(expr: &Expr) -> bool { - // see https://github.com/rust-lang/rust/blob/2679c38fc/src/librustc_ast/util/classify.rs#L7-L25 - match expr { - Expr::Unsafe(_) - | Expr::Block(_) - | Expr::If(_) - | Expr::Match(_) - | Expr::While(_) - | Expr::Loop(_) - | Expr::ForLoop(_) - | Expr::Async(_) - | Expr::TryBlock(_) => false, - _ => true, - } -} - -// Expressions that syntactically contain an "exterior" struct literal i.e. not -// surrounded by any parens or other delimiters. For example `X { y: 1 }`, `X { -// y: 1 }.method()`, `foo == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X -// { y: 1 }) == foo` does not. -fn contains_exterior_struct_lit(expr: &Expr) -> bool { - match expr { - Expr::Struct(_) => true, - - Expr::Assign(ExprAssign { left, right, .. }) - | Expr::AssignOp(ExprAssignOp { left, right, .. }) - | Expr::Binary(ExprBinary { left, right, .. }) => { - // X { y: 1 } + X { y: 2 } - contains_exterior_struct_lit(left) || contains_exterior_struct_lit(right) - } - - Expr::Await(ExprAwait { base: e, .. }) - | Expr::Box(ExprBox { expr: e, .. }) - | Expr::Cast(ExprCast { expr: e, .. }) - | Expr::Field(ExprField { base: e, .. }) - | Expr::Index(ExprIndex { expr: e, .. }) - | Expr::MethodCall(ExprMethodCall { receiver: e, .. }) - | Expr::Reference(ExprReference { expr: e, .. }) - | Expr::Type(ExprType { expr: e, .. }) - | Expr::Unary(ExprUnary { expr: e, .. }) => { - // &X { y: 1 }, X { y: 1 }.y - contains_exterior_struct_lit(e) - } - - _ => false, - } -} - -fn needs_newline_if_wrap(expr: &Expr) -> bool { - match expr { - Expr::Array(_) - | Expr::Async(_) - | Expr::Block(_) - | Expr::Break(ExprBreak { expr: None, .. }) - | Expr::Closure(_) - | Expr::Continue(_) - | Expr::ForLoop(_) - | Expr::If(_) - | Expr::Lit(_) - | Expr::Loop(_) - | Expr::Macro(_) - | Expr::Match(_) - | Expr::Path(_) - | Expr::Range(ExprRange { to: None, .. }) - | Expr::Repeat(_) - | Expr::Return(ExprReturn { expr: None, .. }) - | Expr::Struct(_) - | Expr::TryBlock(_) - | Expr::Tuple(_) - | Expr::Unsafe(_) - | Expr::Verbatim(_) - | Expr::While(_) - | Expr::Yield(ExprYield { expr: None, .. }) => false, - - Expr::Assign(_) - | Expr::AssignOp(_) - | Expr::Await(_) - | Expr::Binary(_) - | Expr::Cast(_) - | Expr::Field(_) - | Expr::Index(_) - | Expr::MethodCall(_) - | Expr::Type(_) => true, - - Expr::Box(ExprBox { expr: e, .. }) - | Expr::Break(ExprBreak { expr: Some(e), .. }) - | Expr::Call(ExprCall { func: e, .. }) - | Expr::Group(ExprGroup { expr: e, .. }) - | Expr::Let(ExprLet { expr: e, .. }) - | Expr::Paren(ExprParen { expr: e, .. }) - | Expr::Range(ExprRange { to: Some(e), .. }) - | Expr::Reference(ExprReference { expr: e, .. }) - | Expr::Return(ExprReturn { expr: Some(e), .. }) - | Expr::Try(ExprTry { expr: e, .. }) - | Expr::Unary(ExprUnary { expr: e, .. }) - | Expr::Yield(ExprYield { expr: Some(e), .. }) => needs_newline_if_wrap(e), - - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => false, - } -} - -fn is_short_ident(expr: &Expr) -> bool { - if let Expr::Path(expr) = expr { - if expr.attrs.is_empty() - && expr.qself.is_none() - && expr.path.leading_colon.is_none() - && expr.path.segments.len() == 1 - && expr.path.segments[0].ident.to_string().len() as isize <= INDENT - { - if let PathArguments::None = expr.path.segments[0].arguments { - return true; - } - } - } - false -} diff --git a/packages/autofmt/src/prettyplease/file.rs b/packages/autofmt/src/prettyplease/file.rs deleted file mode 100644 index 51eece54c..000000000 --- a/packages/autofmt/src/prettyplease/file.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::algorithm::Printer; -use syn::File; - -impl Printer { - pub fn file(&mut self, file: &File) { - self.cbox(0); - if let Some(shebang) = &file.shebang { - self.word(shebang.clone()); - self.hardbreak(); - } - self.inner_attrs(&file.attrs); - for item in &file.items { - self.item(item); - } - self.end(); - } -} diff --git a/packages/autofmt/src/prettyplease/generics.rs b/packages/autofmt/src/prettyplease/generics.rs deleted file mode 100644 index ded973b08..000000000 --- a/packages/autofmt/src/prettyplease/generics.rs +++ /dev/null @@ -1,280 +0,0 @@ -use super::algorithm::Printer; -use super::iter::IterDelimited; -use super::INDENT; -use syn::{ - BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq, - PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, - WhereClause, WherePredicate, -}; - -impl Printer { - pub fn generics(&mut self, generics: &Generics) { - if generics.params.is_empty() { - return; - } - - self.word("<"); - self.cbox(0); - self.zerobreak(); - - // Print lifetimes before types and consts, regardless of their - // order in self.params. - // - // TODO: ordering rules for const parameters vs type parameters have - // not been settled yet. https://github.com/rust-lang/rust/issues/44580 - for param in generics.params.iter().delimited() { - if let GenericParam::Lifetime(_) = *param { - self.generic_param(¶m); - self.trailing_comma(param.is_last); - } - } - for param in generics.params.iter().delimited() { - match *param { - GenericParam::Type(_) | GenericParam::Const(_) => { - self.generic_param(¶m); - self.trailing_comma(param.is_last); - } - GenericParam::Lifetime(_) => {} - } - } - - self.offset(-INDENT); - self.end(); - self.word(">"); - } - - fn generic_param(&mut self, generic_param: &GenericParam) { - match generic_param { - GenericParam::Type(type_param) => self.type_param(type_param), - GenericParam::Lifetime(lifetime_def) => self.lifetime_def(lifetime_def), - GenericParam::Const(const_param) => self.const_param(const_param), - } - } - - pub fn bound_lifetimes(&mut self, bound_lifetimes: &BoundLifetimes) { - self.word("for<"); - for lifetime_def in bound_lifetimes.lifetimes.iter().delimited() { - self.lifetime_def(&lifetime_def); - if !lifetime_def.is_last { - self.word(", "); - } - } - self.word("> "); - } - - fn lifetime_def(&mut self, lifetime_def: &LifetimeDef) { - self.outer_attrs(&lifetime_def.attrs); - self.lifetime(&lifetime_def.lifetime); - for lifetime in lifetime_def.bounds.iter().delimited() { - if lifetime.is_first { - self.word(": "); - } else { - self.word(" + "); - } - self.lifetime(&lifetime); - } - } - - fn type_param(&mut self, type_param: &TypeParam) { - self.outer_attrs(&type_param.attrs); - self.ident(&type_param.ident); - self.ibox(INDENT); - for type_param_bound in type_param.bounds.iter().delimited() { - if type_param_bound.is_first { - self.word(": "); - } else { - self.space(); - self.word("+ "); - } - self.type_param_bound(&type_param_bound); - } - if let Some(default) = &type_param.default { - self.space(); - self.word("= "); - self.ty(default); - } - self.end(); - } - - pub fn type_param_bound(&mut self, type_param_bound: &TypeParamBound) { - match type_param_bound { - TypeParamBound::Trait(trait_bound) => self.trait_bound(trait_bound), - TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime), - } - } - - fn trait_bound(&mut self, trait_bound: &TraitBound) { - if trait_bound.paren_token.is_some() { - self.word("("); - } - let skip = match trait_bound.path.segments.first() { - Some(segment) if segment.ident == "const" => { - self.word("~const "); - 1 - } - _ => 0, - }; - self.trait_bound_modifier(&trait_bound.modifier); - if let Some(bound_lifetimes) = &trait_bound.lifetimes { - self.bound_lifetimes(bound_lifetimes); - } - for segment in trait_bound.path.segments.iter().skip(skip).delimited() { - if !segment.is_first || trait_bound.path.leading_colon.is_some() { - self.word("::"); - } - self.path_segment(&segment); - } - if trait_bound.paren_token.is_some() { - self.word(")"); - } - } - - fn trait_bound_modifier(&mut self, trait_bound_modifier: &TraitBoundModifier) { - match trait_bound_modifier { - TraitBoundModifier::None => {} - TraitBoundModifier::Maybe(_question_mark) => self.word("?"), - } - } - - fn const_param(&mut self, const_param: &ConstParam) { - self.outer_attrs(&const_param.attrs); - self.word("const "); - self.ident(&const_param.ident); - self.word(": "); - self.ty(&const_param.ty); - if let Some(default) = &const_param.default { - self.word(" = "); - self.expr(default); - } - } - - pub fn where_clause_for_body(&mut self, where_clause: &Option) { - let hardbreaks = true; - let semi = false; - self.where_clause_impl(where_clause, hardbreaks, semi); - } - - pub fn where_clause_semi(&mut self, where_clause: &Option) { - let hardbreaks = true; - let semi = true; - self.where_clause_impl(where_clause, hardbreaks, semi); - } - - pub fn where_clause_oneline(&mut self, where_clause: &Option) { - let hardbreaks = false; - let semi = false; - self.where_clause_impl(where_clause, hardbreaks, semi); - } - - pub fn where_clause_oneline_semi(&mut self, where_clause: &Option) { - let hardbreaks = false; - let semi = true; - self.where_clause_impl(where_clause, hardbreaks, semi); - } - - fn where_clause_impl( - &mut self, - where_clause: &Option, - hardbreaks: bool, - semi: bool, - ) { - let where_clause = match where_clause { - Some(where_clause) if !where_clause.predicates.is_empty() => where_clause, - _ => { - if semi { - self.word(";"); - } else { - self.nbsp(); - } - return; - } - }; - if hardbreaks { - self.hardbreak(); - self.offset(-INDENT); - self.word("where"); - self.hardbreak(); - for predicate in where_clause.predicates.iter().delimited() { - self.where_predicate(&predicate); - if predicate.is_last && semi { - self.word(";"); - } else { - self.word(","); - self.hardbreak(); - } - } - if !semi { - self.offset(-INDENT); - } - } else { - self.space(); - self.offset(-INDENT); - self.word("where"); - self.space(); - for predicate in where_clause.predicates.iter().delimited() { - self.where_predicate(&predicate); - if predicate.is_last && semi { - self.word(";"); - } else { - self.trailing_comma_or_space(predicate.is_last); - } - } - if !semi { - self.offset(-INDENT); - } - } - } - - fn where_predicate(&mut self, predicate: &WherePredicate) { - match predicate { - WherePredicate::Type(predicate) => self.predicate_type(predicate), - WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate), - WherePredicate::Eq(predicate) => self.predicate_eq(predicate), - } - } - - fn predicate_type(&mut self, predicate: &PredicateType) { - if let Some(bound_lifetimes) = &predicate.lifetimes { - self.bound_lifetimes(bound_lifetimes); - } - self.ty(&predicate.bounded_ty); - self.word(":"); - if predicate.bounds.len() == 1 { - self.ibox(0); - } else { - self.ibox(INDENT); - } - for type_param_bound in predicate.bounds.iter().delimited() { - if type_param_bound.is_first { - self.nbsp(); - } else { - self.space(); - self.word("+ "); - } - self.type_param_bound(&type_param_bound); - } - self.end(); - } - - fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) { - self.lifetime(&predicate.lifetime); - self.word(":"); - self.ibox(INDENT); - for lifetime in predicate.bounds.iter().delimited() { - if lifetime.is_first { - self.nbsp(); - } else { - self.space(); - self.word("+ "); - } - self.lifetime(&lifetime); - } - self.end(); - } - - fn predicate_eq(&mut self, predicate: &PredicateEq) { - self.ty(&predicate.lhs_ty); - self.word(" = "); - self.ty(&predicate.rhs_ty); - } -} diff --git a/packages/autofmt/src/prettyplease/item.rs b/packages/autofmt/src/prettyplease/item.rs deleted file mode 100644 index 5512137d9..000000000 --- a/packages/autofmt/src/prettyplease/item.rs +++ /dev/null @@ -1,757 +0,0 @@ -use super::algorithm::Printer; -use super::iter::IterDelimited; -use super::INDENT; -use proc_macro2::TokenStream; -use syn::{ - Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, - ForeignItemType, ImplItem, ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, Item, - ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMacro2, - ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Pat, - Receiver, Signature, Stmt, TraitItem, TraitItemConst, TraitItemMacro, TraitItemMethod, - TraitItemType, Type, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, -}; - -impl Printer { - pub fn item(&mut self, item: &Item) { - match item { - Item::Const(item) => self.item_const(item), - Item::Enum(item) => self.item_enum(item), - Item::ExternCrate(item) => self.item_extern_crate(item), - Item::Fn(item) => self.item_fn(item), - Item::ForeignMod(item) => self.item_foreign_mod(item), - Item::Impl(item) => self.item_impl(item), - Item::Macro(item) => self.item_macro(item), - Item::Macro2(item) => self.item_macro2(item), - Item::Mod(item) => self.item_mod(item), - Item::Static(item) => self.item_static(item), - Item::Struct(item) => self.item_struct(item), - Item::Trait(item) => self.item_trait(item), - Item::TraitAlias(item) => self.item_trait_alias(item), - Item::Type(item) => self.item_type(item), - Item::Union(item) => self.item_union(item), - Item::Use(item) => self.item_use(item), - Item::Verbatim(item) => self.item_verbatim(item), - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => unimplemented!("unknown Item"), - } - } - - fn item_const(&mut self, item: &ItemConst) { - self.outer_attrs(&item.attrs); - self.cbox(0); - self.visibility(&item.vis); - self.word("const "); - self.ident(&item.ident); - self.word(": "); - self.ty(&item.ty); - self.word(" = "); - self.neverbreak(); - self.expr(&item.expr); - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn item_enum(&mut self, item: &ItemEnum) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - self.word("enum "); - self.ident(&item.ident); - self.generics(&item.generics); - self.where_clause_for_body(&item.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - for variant in &item.variants { - self.variant(variant); - self.word(","); - self.hardbreak(); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.hardbreak(); - } - - fn item_extern_crate(&mut self, item: &ItemExternCrate) { - self.outer_attrs(&item.attrs); - self.visibility(&item.vis); - self.word("extern crate "); - self.ident(&item.ident); - if let Some((_as_token, rename)) = &item.rename { - self.word(" as "); - self.ident(rename); - } - self.word(";"); - self.hardbreak(); - } - - fn item_fn(&mut self, item: &ItemFn) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - self.signature(&item.sig); - self.where_clause_for_body(&item.sig.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - self.inner_attrs(&item.attrs); - for stmt in &item.block.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.hardbreak(); - } - - fn item_foreign_mod(&mut self, item: &ItemForeignMod) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.abi(&item.abi); - self.word("{"); - self.hardbreak_if_nonempty(); - self.inner_attrs(&item.attrs); - for foreign_item in &item.items { - self.foreign_item(foreign_item); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.hardbreak(); - } - - fn item_impl(&mut self, item: &ItemImpl) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.ibox(-INDENT); - self.cbox(INDENT); - if item.defaultness.is_some() { - self.word("default "); - } - if item.unsafety.is_some() { - self.word("unsafe "); - } - self.word("impl"); - self.generics(&item.generics); - self.end(); - self.nbsp(); - if let Some((negative_polarity, path, _for_token)) = &item.trait_ { - if negative_polarity.is_some() { - self.word("!"); - } - self.path(path); - self.space(); - self.word("for "); - } - self.ty(&item.self_ty); - self.end(); - self.where_clause_for_body(&item.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - self.inner_attrs(&item.attrs); - for impl_item in &item.items { - self.impl_item(impl_item); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.hardbreak(); - } - - fn item_macro(&mut self, item: &ItemMacro) { - self.outer_attrs(&item.attrs); - self.mac(&item.mac, item.ident.as_ref()); - self.mac_semi_if_needed(&item.mac.delimiter); - self.hardbreak(); - } - - fn item_macro2(&mut self, item: &ItemMacro2) { - unimplemented!("Item::Macro2 `macro {} {}`", item.ident, item.rules); - } - - fn item_mod(&mut self, item: &ItemMod) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - self.word("mod "); - self.ident(&item.ident); - if let Some((_brace, items)) = &item.content { - self.word(" {"); - self.hardbreak_if_nonempty(); - self.inner_attrs(&item.attrs); - for item in items { - self.item(item); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } else { - self.word(";"); - self.end(); - } - self.hardbreak(); - } - - fn item_static(&mut self, item: &ItemStatic) { - self.outer_attrs(&item.attrs); - self.cbox(0); - self.visibility(&item.vis); - self.word("static "); - if item.mutability.is_some() { - self.word("mut "); - } - self.ident(&item.ident); - self.word(": "); - self.ty(&item.ty); - self.word(" = "); - self.neverbreak(); - self.expr(&item.expr); - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn item_struct(&mut self, item: &ItemStruct) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - self.word("struct "); - self.ident(&item.ident); - self.generics(&item.generics); - match &item.fields { - Fields::Named(fields) => { - self.where_clause_for_body(&item.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - for field in &fields.named { - self.field(field); - self.word(","); - self.hardbreak(); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } - Fields::Unnamed(fields) => { - self.fields_unnamed(fields); - self.where_clause_semi(&item.generics.where_clause); - self.end(); - } - Fields::Unit => { - self.where_clause_semi(&item.generics.where_clause); - self.end(); - } - } - self.hardbreak(); - } - - fn item_trait(&mut self, item: &ItemTrait) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - if item.unsafety.is_some() { - self.word("unsafe "); - } - if item.auto_token.is_some() { - self.word("auto "); - } - self.word("trait "); - self.ident(&item.ident); - self.generics(&item.generics); - for supertrait in item.supertraits.iter().delimited() { - if supertrait.is_first { - self.word(": "); - } else { - self.word(" + "); - } - self.type_param_bound(&supertrait); - } - self.where_clause_for_body(&item.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - self.inner_attrs(&item.attrs); - for trait_item in &item.items { - self.trait_item(trait_item); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.hardbreak(); - } - - fn item_trait_alias(&mut self, item: &ItemTraitAlias) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - self.word("trait "); - self.ident(&item.ident); - self.generics(&item.generics); - self.word(" = "); - self.neverbreak(); - for bound in item.bounds.iter().delimited() { - if !bound.is_first { - self.space(); - self.word("+ "); - } - self.type_param_bound(&bound); - } - self.where_clause_semi(&item.generics.where_clause); - self.end(); - self.hardbreak(); - } - - fn item_type(&mut self, item: &ItemType) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - self.word("type "); - self.ident(&item.ident); - self.generics(&item.generics); - self.where_clause_oneline(&item.generics.where_clause); - self.word("= "); - self.neverbreak(); - self.ibox(-INDENT); - self.ty(&item.ty); - self.end(); - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn item_union(&mut self, item: &ItemUnion) { - self.outer_attrs(&item.attrs); - self.cbox(INDENT); - self.visibility(&item.vis); - self.word("union "); - self.ident(&item.ident); - self.generics(&item.generics); - self.where_clause_for_body(&item.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - for field in &item.fields.named { - self.field(field); - self.word(","); - self.hardbreak(); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.hardbreak(); - } - - fn item_use(&mut self, item: &ItemUse) { - self.outer_attrs(&item.attrs); - self.visibility(&item.vis); - self.word("use "); - if item.leading_colon.is_some() { - self.word("::"); - } - self.use_tree(&item.tree); - self.word(";"); - self.hardbreak(); - } - - fn item_verbatim(&mut self, item: &TokenStream) { - if !item.is_empty() { - unimplemented!("Item::Verbatim `{}`", item); - } - self.hardbreak(); - } - - fn use_tree(&mut self, use_tree: &UseTree) { - match use_tree { - UseTree::Path(use_path) => self.use_path(use_path), - UseTree::Name(use_name) => self.use_name(use_name), - UseTree::Rename(use_rename) => self.use_rename(use_rename), - UseTree::Glob(use_glob) => self.use_glob(use_glob), - UseTree::Group(use_group) => self.use_group(use_group), - } - } - - fn use_path(&mut self, use_path: &UsePath) { - self.ident(&use_path.ident); - self.word("::"); - self.use_tree(&use_path.tree); - } - - fn use_name(&mut self, use_name: &UseName) { - self.ident(&use_name.ident); - } - - fn use_rename(&mut self, use_rename: &UseRename) { - self.ident(&use_rename.ident); - self.word(" as "); - self.ident(&use_rename.rename); - } - - fn use_glob(&mut self, use_glob: &UseGlob) { - let _ = use_glob; - self.word("*"); - } - - fn use_group(&mut self, use_group: &UseGroup) { - if use_group.items.is_empty() { - self.word("{}"); - } else if use_group.items.len() == 1 { - self.use_tree(&use_group.items[0]); - } else { - self.cbox(INDENT); - self.word("{"); - self.zerobreak(); - self.ibox(0); - for use_tree in use_group.items.iter().delimited() { - self.use_tree(&use_tree); - if !use_tree.is_last { - self.word(","); - let mut use_tree = *use_tree; - while let UseTree::Path(use_path) = use_tree { - use_tree = &use_path.tree; - } - if let UseTree::Group(_) = use_tree { - self.hardbreak(); - } else { - self.space(); - } - } - } - self.end(); - self.trailing_comma(true); - self.offset(-INDENT); - self.word("}"); - self.end(); - } - } - - fn foreign_item(&mut self, foreign_item: &ForeignItem) { - match foreign_item { - ForeignItem::Fn(item) => self.foreign_item_fn(item), - ForeignItem::Static(item) => self.foreign_item_static(item), - ForeignItem::Type(item) => self.foreign_item_type(item), - ForeignItem::Macro(item) => self.foreign_item_macro(item), - ForeignItem::Verbatim(item) => self.foreign_item_verbatim(item), - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => unimplemented!("unknown ForeignItem"), - } - } - - fn foreign_item_fn(&mut self, foreign_item: &ForeignItemFn) { - self.outer_attrs(&foreign_item.attrs); - self.cbox(INDENT); - self.visibility(&foreign_item.vis); - self.signature(&foreign_item.sig); - self.where_clause_semi(&foreign_item.sig.generics.where_clause); - self.end(); - self.hardbreak(); - } - - fn foreign_item_static(&mut self, foreign_item: &ForeignItemStatic) { - self.outer_attrs(&foreign_item.attrs); - self.cbox(0); - self.visibility(&foreign_item.vis); - self.word("static "); - if foreign_item.mutability.is_some() { - self.word("mut "); - } - self.ident(&foreign_item.ident); - self.word(": "); - self.ty(&foreign_item.ty); - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn foreign_item_type(&mut self, foreign_item: &ForeignItemType) { - self.outer_attrs(&foreign_item.attrs); - self.cbox(0); - self.visibility(&foreign_item.vis); - self.word("type "); - self.ident(&foreign_item.ident); - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn foreign_item_macro(&mut self, foreign_item: &ForeignItemMacro) { - self.outer_attrs(&foreign_item.attrs); - self.mac(&foreign_item.mac, None); - self.mac_semi_if_needed(&foreign_item.mac.delimiter); - self.hardbreak(); - } - - fn foreign_item_verbatim(&mut self, foreign_item: &TokenStream) { - if !foreign_item.is_empty() { - unimplemented!("ForeignItem::Verbatim `{}`", foreign_item); - } - self.hardbreak(); - } - - fn trait_item(&mut self, trait_item: &TraitItem) { - match trait_item { - TraitItem::Const(item) => self.trait_item_const(item), - TraitItem::Method(item) => self.trait_item_method(item), - TraitItem::Type(item) => self.trait_item_type(item), - TraitItem::Macro(item) => self.trait_item_macro(item), - TraitItem::Verbatim(item) => self.trait_item_verbatim(item), - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => unimplemented!("unknown TraitItem"), - } - } - - fn trait_item_const(&mut self, trait_item: &TraitItemConst) { - self.outer_attrs(&trait_item.attrs); - self.cbox(0); - self.word("const "); - self.ident(&trait_item.ident); - self.word(": "); - self.ty(&trait_item.ty); - if let Some((_eq_token, default)) = &trait_item.default { - self.word(" = "); - self.neverbreak(); - self.expr(default); - } - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn trait_item_method(&mut self, trait_item: &TraitItemMethod) { - self.outer_attrs(&trait_item.attrs); - self.cbox(INDENT); - self.signature(&trait_item.sig); - if let Some(block) = &trait_item.default { - self.where_clause_for_body(&trait_item.sig.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - self.inner_attrs(&trait_item.attrs); - for stmt in &block.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } else { - self.where_clause_semi(&trait_item.sig.generics.where_clause); - self.end(); - } - self.hardbreak(); - } - - fn trait_item_type(&mut self, trait_item: &TraitItemType) { - self.outer_attrs(&trait_item.attrs); - self.cbox(INDENT); - self.word("type "); - self.ident(&trait_item.ident); - self.generics(&trait_item.generics); - for bound in trait_item.bounds.iter().delimited() { - if bound.is_first { - self.word(": "); - } else { - self.space(); - self.word("+ "); - } - self.type_param_bound(&bound); - } - if let Some((_eq_token, default)) = &trait_item.default { - self.where_clause_oneline(&trait_item.generics.where_clause); - self.word("= "); - self.neverbreak(); - self.ty(default); - } else { - self.where_clause_oneline_semi(&trait_item.generics.where_clause); - } - self.end(); - self.hardbreak(); - } - - fn trait_item_macro(&mut self, trait_item: &TraitItemMacro) { - self.outer_attrs(&trait_item.attrs); - self.mac(&trait_item.mac, None); - self.mac_semi_if_needed(&trait_item.mac.delimiter); - self.hardbreak(); - } - - fn trait_item_verbatim(&mut self, trait_item: &TokenStream) { - if !trait_item.is_empty() { - unimplemented!("TraitItem::Verbatim `{}`", trait_item); - } - self.hardbreak(); - } - - fn impl_item(&mut self, impl_item: &ImplItem) { - match impl_item { - ImplItem::Const(item) => self.impl_item_const(item), - ImplItem::Method(item) => self.impl_item_method(item), - ImplItem::Type(item) => self.impl_item_type(item), - ImplItem::Macro(item) => self.impl_item_macro(item), - ImplItem::Verbatim(item) => self.impl_item_verbatim(item), - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => unimplemented!("unknown ImplItem"), - } - } - - fn impl_item_const(&mut self, impl_item: &ImplItemConst) { - self.outer_attrs(&impl_item.attrs); - self.cbox(0); - self.visibility(&impl_item.vis); - if impl_item.defaultness.is_some() { - self.word("default "); - } - self.word("const "); - self.ident(&impl_item.ident); - self.word(": "); - self.ty(&impl_item.ty); - self.word(" = "); - self.neverbreak(); - self.expr(&impl_item.expr); - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn impl_item_method(&mut self, impl_item: &ImplItemMethod) { - self.outer_attrs(&impl_item.attrs); - self.cbox(INDENT); - self.visibility(&impl_item.vis); - if impl_item.defaultness.is_some() { - self.word("default "); - } - self.signature(&impl_item.sig); - if impl_item.block.stmts.len() == 1 { - if let Stmt::Item(Item::Verbatim(verbatim)) = &impl_item.block.stmts[0] { - if verbatim.to_string() == ";" { - self.where_clause_semi(&impl_item.sig.generics.where_clause); - self.end(); - self.hardbreak(); - return; - } - } - } - self.where_clause_for_body(&impl_item.sig.generics.where_clause); - self.word("{"); - self.hardbreak_if_nonempty(); - self.inner_attrs(&impl_item.attrs); - for stmt in &impl_item.block.stmts { - self.stmt(stmt); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - self.hardbreak(); - } - - fn impl_item_type(&mut self, impl_item: &ImplItemType) { - self.outer_attrs(&impl_item.attrs); - self.cbox(INDENT); - self.visibility(&impl_item.vis); - if impl_item.defaultness.is_some() { - self.word("default "); - } - self.word("type "); - self.ident(&impl_item.ident); - self.generics(&impl_item.generics); - self.where_clause_oneline(&impl_item.generics.where_clause); - self.word("= "); - self.neverbreak(); - self.ibox(-INDENT); - self.ty(&impl_item.ty); - self.end(); - self.word(";"); - self.end(); - self.hardbreak(); - } - - fn impl_item_macro(&mut self, impl_item: &ImplItemMacro) { - self.outer_attrs(&impl_item.attrs); - self.mac(&impl_item.mac, None); - self.mac_semi_if_needed(&impl_item.mac.delimiter); - self.hardbreak(); - } - - fn impl_item_verbatim(&mut self, impl_item: &TokenStream) { - if !impl_item.is_empty() { - unimplemented!("ImplItem::Verbatim `{}`", impl_item); - } - self.hardbreak(); - } - - fn maybe_variadic(&mut self, arg: &FnArg) -> bool { - let pat_type = match arg { - FnArg::Typed(pat_type) => pat_type, - FnArg::Receiver(receiver) => { - self.receiver(receiver); - return false; - } - }; - - match pat_type.ty.as_ref() { - Type::Verbatim(ty) if ty.to_string() == "..." => { - match pat_type.pat.as_ref() { - Pat::Verbatim(pat) if pat.to_string() == "..." => { - self.outer_attrs(&pat_type.attrs); - self.word("..."); - } - _ => self.pat_type(pat_type), - } - true - } - _ => { - self.pat_type(pat_type); - false - } - } - } - - fn signature(&mut self, signature: &Signature) { - if signature.constness.is_some() { - self.word("const "); - } - if signature.asyncness.is_some() { - self.word("async "); - } - if signature.unsafety.is_some() { - self.word("unsafe "); - } - if let Some(abi) = &signature.abi { - self.abi(abi); - } - self.word("fn "); - self.ident(&signature.ident); - self.generics(&signature.generics); - self.word("("); - self.neverbreak(); - self.cbox(0); - self.zerobreak(); - let mut last_is_variadic = false; - for input in signature.inputs.iter().delimited() { - last_is_variadic = self.maybe_variadic(&input); - if last_is_variadic { - self.zerobreak(); - } else { - self.trailing_comma(input.is_last); - } - } - if signature.variadic.is_some() && !last_is_variadic { - self.word("..."); - self.zerobreak(); - } - self.offset(-INDENT); - self.end(); - self.word(")"); - self.return_type(&signature.output); - } - - fn receiver(&mut self, receiver: &Receiver) { - self.outer_attrs(&receiver.attrs); - if let Some((_ampersand, lifetime)) = &receiver.reference { - self.word("&"); - if let Some(lifetime) = lifetime { - self.lifetime(lifetime); - self.nbsp(); - } - } - if receiver.mutability.is_some() { - self.word("mut "); - } - self.word("self"); - } -} diff --git a/packages/autofmt/src/prettyplease/iter.rs b/packages/autofmt/src/prettyplease/iter.rs deleted file mode 100644 index 702c653f5..000000000 --- a/packages/autofmt/src/prettyplease/iter.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::iter::Peekable; -use std::ops::Deref; - -pub struct Delimited { - is_first: bool, - iter: Peekable, -} - -pub trait IterDelimited: Iterator + Sized { - fn delimited(self) -> Delimited { - Delimited { - is_first: true, - iter: self.peekable(), - } - } -} - -impl IterDelimited for I {} - -pub struct IteratorItem { - value: T, - pub is_first: bool, - pub is_last: bool, -} - -impl Iterator for Delimited { - type Item = IteratorItem; - - fn next(&mut self) -> Option { - let item = IteratorItem { - value: self.iter.next()?, - is_first: self.is_first, - is_last: self.iter.peek().is_none(), - }; - self.is_first = false; - Some(item) - } -} - -impl Deref for IteratorItem { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} diff --git a/packages/autofmt/src/prettyplease/lifetime.rs b/packages/autofmt/src/prettyplease/lifetime.rs deleted file mode 100644 index 760d5776d..000000000 --- a/packages/autofmt/src/prettyplease/lifetime.rs +++ /dev/null @@ -1,9 +0,0 @@ -use super::algorithm::Printer; -use syn::Lifetime; - -impl Printer { - pub fn lifetime(&mut self, lifetime: &Lifetime) { - self.word("'"); - self.ident(&lifetime.ident); - } -} diff --git a/packages/autofmt/src/prettyplease/lit.rs b/packages/autofmt/src/prettyplease/lit.rs deleted file mode 100644 index 37f2160ad..000000000 --- a/packages/autofmt/src/prettyplease/lit.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::algorithm::Printer; -use proc_macro2::Literal; -use syn::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr}; - -impl Printer { - pub fn lit(&mut self, lit: &Lit) { - match lit { - Lit::Str(lit) => self.lit_str(lit), - Lit::ByteStr(lit) => self.lit_byte_str(lit), - Lit::Byte(lit) => self.lit_byte(lit), - Lit::Char(lit) => self.lit_char(lit), - Lit::Int(lit) => self.lit_int(lit), - Lit::Float(lit) => self.lit_float(lit), - Lit::Bool(lit) => self.lit_bool(lit), - Lit::Verbatim(lit) => self.lit_verbatim(lit), - } - } - - pub fn lit_str(&mut self, lit: &LitStr) { - self.word(lit.token().to_string()); - } - - fn lit_byte_str(&mut self, lit: &LitByteStr) { - self.word(lit.token().to_string()); - } - - fn lit_byte(&mut self, lit: &LitByte) { - self.word(lit.token().to_string()); - } - - fn lit_char(&mut self, lit: &LitChar) { - self.word(lit.token().to_string()); - } - - fn lit_int(&mut self, lit: &LitInt) { - self.word(lit.token().to_string()); - } - - fn lit_float(&mut self, lit: &LitFloat) { - self.word(lit.token().to_string()); - } - - fn lit_bool(&mut self, lit: &LitBool) { - self.word(if lit.value { "true" } else { "false" }); - } - - fn lit_verbatim(&mut self, token: &Literal) { - self.word(token.to_string()); - } -} diff --git a/packages/autofmt/src/prettyplease/mac.rs b/packages/autofmt/src/prettyplease/mac.rs deleted file mode 100644 index 4608bc303..000000000 --- a/packages/autofmt/src/prettyplease/mac.rs +++ /dev/null @@ -1,220 +0,0 @@ -use super::algorithm::Printer; -use super::token::Token; -use super::INDENT; -use proc_macro2::{Delimiter, Spacing, TokenStream}; -use syn::{Ident, Macro, MacroDelimiter, PathArguments}; - -impl Printer { - pub fn mac(&mut self, mac: &Macro, ident: Option<&Ident>) { - let is_macro_rules = mac.path.leading_colon.is_none() - && mac.path.segments.len() == 1 - && matches!(mac.path.segments[0].arguments, PathArguments::None) - && mac.path.segments[0].ident == "macro_rules"; - if is_macro_rules { - if let Some(ident) = ident { - self.macro_rules(ident, &mac.tokens); - return; - } - } - self.path(&mac.path); - self.word("!"); - if let Some(ident) = ident { - self.nbsp(); - self.ident(ident); - } - let (open, close, delimiter_break) = match mac.delimiter { - MacroDelimiter::Paren(_) => ("(", ")", Self::zerobreak as fn(&mut Self)), - MacroDelimiter::Brace(_) => (" {", "}", Self::hardbreak as fn(&mut Self)), - MacroDelimiter::Bracket(_) => ("[", "]", Self::zerobreak as fn(&mut Self)), - }; - self.word(open); - self.cbox(INDENT); - delimiter_break(self); - self.ibox(0); - self.macro_rules_tokens(mac.tokens.clone(), false); - self.end(); - delimiter_break(self); - self.offset(-INDENT); - self.end(); - self.word(close); - } - - pub fn mac_semi_if_needed(&mut self, delimiter: &MacroDelimiter) { - match delimiter { - MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => self.word(";"), - MacroDelimiter::Brace(_) => {} - } - } - - fn macro_rules(&mut self, name: &Ident, rules: &TokenStream) { - enum State { - Start, - Matcher, - Equal, - Greater, - Expander, - } - - use State::*; - - self.word("macro_rules! "); - self.ident(name); - self.word(" {"); - self.cbox(INDENT); - self.hardbreak_if_nonempty(); - let mut state = State::Start; - for tt in rules.clone() { - let token = Token::from(tt); - match (state, token) { - (Start, Token::Group(delimiter, stream)) => { - self.delimiter_open(delimiter); - if !stream.is_empty() { - self.cbox(INDENT); - self.zerobreak(); - self.ibox(0); - self.macro_rules_tokens(stream, true); - self.end(); - self.zerobreak(); - self.offset(-INDENT); - self.end(); - } - self.delimiter_close(delimiter); - state = Matcher; - } - (Matcher, Token::Punct('=', Spacing::Joint)) => { - self.word(" ="); - state = Equal; - } - (Equal, Token::Punct('>', Spacing::Alone)) => { - self.word(">"); - state = Greater; - } - (Greater, Token::Group(_delimiter, stream)) => { - self.word(" {"); - self.neverbreak(); - if !stream.is_empty() { - self.cbox(INDENT); - self.hardbreak(); - self.ibox(0); - self.macro_rules_tokens(stream, false); - self.end(); - self.hardbreak(); - self.offset(-INDENT); - self.end(); - } - self.word("}"); - state = Expander; - } - (Expander, Token::Punct(';', Spacing::Alone)) => { - self.word(";"); - self.hardbreak(); - state = Start; - } - _ => unimplemented!("bad macro_rules syntax"), - } - } - match state { - Start => {} - Expander => { - self.word(";"); - self.hardbreak(); - } - _ => self.hardbreak(), - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } - - fn macro_rules_tokens(&mut self, stream: TokenStream, matcher: bool) { - #[derive(PartialEq)] - enum State { - Start, - Dollar, - DollarIdent, - DollarIdentColon, - DollarParen, - DollarParenSep, - Pound, - PoundBang, - Dot, - Colon, - Colon2, - Ident, - IdentBang, - Delim, - Other, - } - - use State::*; - - let mut state = Start; - let mut previous_is_joint = true; - for tt in stream { - let token = Token::from(tt); - let (needs_space, next_state) = match (&state, &token) { - (Dollar, Token::Ident(_)) => (false, if matcher { DollarIdent } else { Other }), - (DollarIdent, Token::Punct(':', Spacing::Alone)) => (false, DollarIdentColon), - (DollarIdentColon, Token::Ident(_)) => (false, Other), - (DollarParen, Token::Punct('+' | '*' | '?', Spacing::Alone)) => (false, Other), - (DollarParen, Token::Ident(_) | Token::Literal(_)) => (false, DollarParenSep), - (DollarParen, Token::Punct(_, Spacing::Joint)) => (false, DollarParen), - (DollarParen, Token::Punct(_, Spacing::Alone)) => (false, DollarParenSep), - (DollarParenSep, Token::Punct('+' | '*', _)) => (false, Other), - (Pound, Token::Punct('!', _)) => (false, PoundBang), - (Dollar, Token::Group(Delimiter::Parenthesis, _)) => (false, DollarParen), - (Pound | PoundBang, Token::Group(Delimiter::Bracket, _)) => (false, Other), - (Ident, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => { - (false, Delim) - } - (Ident, Token::Punct('!', Spacing::Alone)) => (false, IdentBang), - (IdentBang, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => { - (false, Other) - } - (Colon, Token::Punct(':', _)) => (false, Colon2), - (_, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => (true, Delim), - (_, Token::Group(Delimiter::Brace | Delimiter::None, _)) => (true, Other), - (_, Token::Ident(ident)) if !is_keyword(ident) => { - (state != Dot && state != Colon2, Ident) - } - (_, Token::Literal(_)) => (state != Dot, Ident), - (_, Token::Punct(',' | ';', _)) => (false, Other), - (_, Token::Punct('.', _)) if !matcher => (state != Ident && state != Delim, Dot), - (_, Token::Punct(':', Spacing::Joint)) => (state != Ident, Colon), - (_, Token::Punct('$', _)) => (true, Dollar), - (_, Token::Punct('#', _)) => (true, Pound), - (_, _) => (true, Other), - }; - if !previous_is_joint { - if needs_space { - self.space(); - } else if let Token::Punct('.', _) = token { - self.zerobreak(); - } - } - previous_is_joint = match token { - Token::Punct(_, Spacing::Joint) | Token::Punct('$', _) => true, - _ => false, - }; - self.single_token( - token, - if matcher { - |printer, stream| printer.macro_rules_tokens(stream, true) - } else { - |printer, stream| printer.macro_rules_tokens(stream, false) - }, - ); - state = next_state; - } - } -} - -fn is_keyword(ident: &Ident) -> bool { - match ident.to_string().as_str() { - "as" | "box" | "break" | "const" | "continue" | "crate" | "else" | "enum" | "extern" - | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" - | "move" | "mut" | "pub" | "ref" | "return" | "static" | "struct" | "trait" | "type" - | "unsafe" | "use" | "where" | "while" | "yield" => true, - _ => false, - } -} diff --git a/packages/autofmt/src/prettyplease/mod.rs b/packages/autofmt/src/prettyplease/mod.rs deleted file mode 100644 index 68d8e1303..000000000 --- a/packages/autofmt/src/prettyplease/mod.rs +++ /dev/null @@ -1,381 +0,0 @@ -//! [![github]](https://github.com/dtolnay/prettyplease) [![crates-io]](https://crates.io/crates/prettyplease) [![docs-rs]](https://docs.rs/prettyplease) -//! -//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github -//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust -//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K -//! -//!
-//! -//! **prettyplease::unparse** — a minimal `syn` syntax tree pretty-printer -//! -//!
-//! -//! # Overview -//! -//! This is a pretty-printer to turn a `syn` syntax tree into a `String` of -//! well-formatted source code. In contrast to rustfmt, this library is intended -//! to be suitable for arbitrary generated code. -//! -//! Rustfmt prioritizes high-quality output that is impeccable enough that you'd -//! be comfortable spending your career staring at its output — but that -//! means some heavyweight algorithms, and it has a tendency to bail out on code -//! that is hard to format (for example [rustfmt#3697], and there are dozens -//! more issues like it). That's not necessarily a big deal for human-generated -//! code because when code gets highly nested, the human will naturally be -//! inclined to refactor into more easily formattable code. But for generated -//! code, having the formatter just give up leaves it totally unreadable. -//! -//! [rustfmt#3697]: https://github.com/rust-lang/rustfmt/issues/3697 -//! -//! This library is designed using the simplest possible algorithm and data -//! structures that can deliver about 95% of the quality of rustfmt-formatted -//! output. In my experience testing real-world code, approximately 97-98% of -//! output lines come out identical between rustfmt's formatting and this -//! crate's. The rest have slightly different linebreak decisions, but still -//! clearly follow the dominant modern Rust style. -//! -//! The tradeoffs made by this crate are a good fit for generated code that you -//! will *not* spend your career staring at. For example, the output of -//! `bindgen`, or the output of `cargo-expand`. In those cases it's more -//! important that the whole thing be formattable without the formatter giving -//! up, than that it be flawless. -//! -//!
-//! -//! # Feature matrix -//! -//! Here are a few superficial comparisons of this crate against the AST -//! pretty-printer built into rustc, and rustfmt. The sections below go into -//! more detail comparing the output of each of these libraries. -//! -//! | | prettyplease | rustc | rustfmt | -//! | --- | --- | --- | --- | -//! | non-pathological behavior on big or generated code | ✅ | ❌ | ❌ | -//! | idiomatic modern formatting ("locally indistinguishable from rustfmt") | ✅ | ❌ | ✅ | -//! | throughput | 60 MB/s | 39 MB/s | 2.8 MB/s | -//! | number of dependencies | 3 | 72 | 66 | -//! | compile time including dependencies | 2.4 sec | 23.1 sec | 29.8 sec | -//! | buildable using a stable Rust compiler | ✅ | ❌ | ❌ | -//! | published to crates.io | ✅ | ❌ | ❌ | -//! | extensively configurable output | ❌ | ❌ | ✅ | -//! | intended to accommodate hand-maintained source code | ❌ | ❌ | ✅ | -//! -//!
-//! -//! # Comparison to rustfmt -//! -//! - [input.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/input.rs) -//! - [output.prettyplease.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.prettyplease.rs) -//! - [output.rustfmt.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.rustfmt.rs) -//! -//! If you weren't told which output file is which, it would be practically -//! impossible to tell — **except** for line 435 in the rustfmt output, -//! which is more than 1000 characters long because rustfmt just gave up -//! formatting that part of the file: -//! -//! ``` -//! # const _: &str = stringify! {{{ -//! match segments[5] { -//! 0 => write!(f, "::{}", ipv4), -//! 0xffff => write!(f, "::ffff:{}", ipv4), -//! _ => unreachable!(), -//! } -//! } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } } -//! } else { -//! const IPV6_BUF_LEN: usize = (4 * 8) + 7; -//! let mut buf = [0u8; IPV6_BUF_LEN]; -//! let mut buf_slice = &mut buf[..]; -//! # }}; -//! ``` -//! -//! This is a pretty typical manifestation of rustfmt bailing out in generated -//! code — a chunk of the input ends up on one line. The other -//! manifestation is that you're working on some code, running rustfmt on save -//! like a conscientious developer, but after a while notice it isn't doing -//! anything. You introduce an intentional formatting issue, like a stray indent -//! or semicolon, and run rustfmt to check your suspicion. Nope, it doesn't get -//! cleaned up — rustfmt is just not formatting the part of the file you -//! are working on. -//! -//! The prettyplease library is designed to have no pathological cases that -//! force a bail out; the entire input you give it will get formatted in some -//! "good enough" form. -//! -//! Separately, rustfmt can be problematic to integrate into projects. It's -//! written using rustc's internal syntax tree, so it can't be built by a stable -//! compiler. Its releases are not regularly published to crates.io, so in Cargo -//! builds you'd need to depend on it as a git dependency, which precludes -//! publishing your crate to crates.io also. You can shell out to a `rustfmt` -//! binary, but that'll be whatever rustfmt version is installed on each -//! developer's system (if any), which can lead to spurious diffs in checked-in -//! generated code formatted by different versions. In contrast prettyplease is -//! designed to be easy to pull in as a library, and compiles fast. -//! -//!
-//! -//! # Comparison to rustc_ast_pretty -//! -//! - [input.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/input.rs) -//! - [output.prettyplease.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.prettyplease.rs) -//! - [output.rustc.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.rustc.rs) -//! -//! This is the pretty-printer that gets used when rustc prints source code, -//! such as `rustc -Zunpretty=expanded`. It's used also by the standard -//! library's `stringify!` when stringifying an interpolated macro_rules AST -//! fragment, like an $:expr, and transitively by `dbg!` and many macros in the -//! ecosystem. -//! -//! Rustc's formatting is mostly okay, but does not hew closely to the dominant -//! contemporary style of Rust formatting. Some things wouldn't ever be written -//! on one line, like this `match` expression, and certainly not with a comma in -//! front of the closing brace: -//! -//! ``` -//! # const _: &str = stringify! { -//! fn eq(&self, other: &IpAddr) -> bool { -//! match other { IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, } -//! } -//! # }; -//! ``` -//! -//! Some places use non-multiple-of-4 indentation, which is definitely not the -//! norm: -//! -//! ``` -//! # const _: &str = stringify! { -//! pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { -//! let [a, b, c, d] = self.octets(); -//! Ipv6Addr{inner: -//! c::in6_addr{s6_addr: -//! [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, -//! 0xFF, a, b, c, d],},} -//! } -//! # }; -//! ``` -//! -//! And although there isn't an egregious example of it in the link because the -//! input code is pretty tame, in general rustc_ast_pretty has pathological -//! behavior on generated code. It has a tendency to use excessive horizontal -//! indentation and rapidly run out of width: -//! -//! ``` -//! # const _: &str = stringify! { -//! ::std::io::_print(::core::fmt::Arguments::new_v1(&[""], -//! &match (&msg,) { -//! _args => -//! [::core::fmt::ArgumentV1::new(_args.0, -//! ::core::fmt::Display::fmt)], -//! })); -//! # }; -//! ``` -//! -//! The snippets above are clearly different from modern rustfmt style. In -//! contrast, prettyplease is designed to have output that is practically -//! indistinguishable from rustfmt-formatted code. -//! -//!
-//! -//! # Example -//! -//! ``` -//! // [dependencies] -//! // prettyplease = "0.1" -//! // syn = { version = "1", default-features = false, features = ["full", "parsing"] } -//! -//! const INPUT: &str = stringify! { -//! use super::{ -//! lazy::{Lazy, SyncLazy, SyncOnceCell}, panic, -//! sync::{ atomic::{AtomicUsize, Ordering::SeqCst}, -//! mpsc::channel, Mutex, }, -//! thread, -//! }; -//! impl Into for T where U: From { -//! fn into(self) -> U { U::from(self) } -//! } -//! }; -//! -//! fn main() { -//! let syntax_tree = syn::parse_file(INPUT).unwrap(); -//! let formatted = prettyplease::unparse(&syntax_tree); -//! print!("{}", formatted); -//! } -//! ``` -//! -//!
-//! -//! # Algorithm notes -//! -//! The approach and terminology used in the implementation are derived from -//! [*Derek C. Oppen, "Pretty Printing" (1979)*][paper], on which -//! rustc_ast_pretty is also based, and from rustc_ast_pretty's implementation -//! written by Graydon Hoare in 2011 (and modernized over the years by dozens of -//! volunteer maintainers). -//! -//! [paper]: http://i.stanford.edu/pub/cstr/reports/cs/tr/79/770/CS-TR-79-770.pdf -//! -//! The paper describes two language-agnostic interacting procedures `Scan()` -//! and `Print()`. Language-specific code decomposes an input data structure -//! into a stream of `string` and `break` tokens, and `begin` and `end` tokens -//! for grouping. Each `begin`–`end` range may be identified as either -//! "consistent breaking" or "inconsistent breaking". If a group is consistently -//! breaking, then if the whole contents do not fit on the line, *every* `break` -//! token in the group will receive a linebreak. This is appropriate, for -//! example, for Rust struct literals, or arguments of a function call. If a -//! group is inconsistently breaking, then the `string` tokens in the group are -//! greedily placed on the line until out of space, and linebroken only at those -//! `break` tokens for which the next string would not fit. For example, this is -//! appropriate for the contents of a braced `use` statement in Rust. -//! -//! Scan's job is to efficiently accumulate sizing information about groups and -//! breaks. For every `begin` token we compute the distance to the matched `end` -//! token, and for every `break` we compute the distance to the next `break`. -//! The algorithm uses a ringbuffer to hold tokens whose size is not yet -//! ascertained. The maximum size of the ringbuffer is bounded by the target -//! line length and does not grow indefinitely, regardless of deep nesting in -//! the input stream. That's because once a group is sufficiently big, the -//! precise size can no longer make a difference to linebreak decisions and we -//! can effectively treat it as "infinity". -//! -//! Print's job is to use the sizing information to efficiently assign a -//! "broken" or "not broken" status to every `begin` token. At that point the -//! output is easily constructed by concatenating `string` tokens and breaking -//! at `break` tokens contained within a broken group. -//! -//! Leveraging these primitives (i.e. cleverly placing the all-or-nothing -//! consistent breaks and greedy inconsistent breaks) to yield -//! rustfmt-compatible formatting for all of Rust's syntax tree nodes is a fun -//! challenge. -//! -//! Here is a visualization of some Rust tokens fed into the pretty printing -//! algorithm. Consistently breaking `begin`—`end` pairs are represented -//! by `«`⁠`»`, inconsistently breaking by `‹`⁠`›`, `break` by `·`, -//! and the rest of the non-whitespace are `string`. -//! -//! ```text -//! use super::«{· -//! ‹ lazy::«{·‹Lazy,· SyncLazy,· SyncOnceCell›·}»,· -//! panic,· -//! sync::«{· -//! ‹ atomic::«{·‹AtomicUsize,· Ordering::SeqCst›·}»,· -//! mpsc::channel,· Mutex›,· -//! }»,· -//! thread›,· -//! }»;· -//! «‹«impl<«·T‹›,· U‹›·»>» Into<«·U·»>· for T›· -//! where· -//! U:‹ From<«·T·»>›,· -//! {· -//! « fn into(·«·self·») -> U {· -//! ‹ U::from(«·self·»)›· -//! » }· -//! »}· -//! ``` -//! -//! The algorithm described in the paper is not quite sufficient for producing -//! well-formatted Rust code that is locally indistinguishable from rustfmt's -//! style. The reason is that in the paper, the complete non-whitespace contents -//! are assumed to be independent of linebreak decisions, with Scan and Print -//! being only in control of the whitespace (spaces and line breaks). In Rust as -//! idiomatically formattted by rustfmt, that is not the case. Trailing commas -//! are one example; the punctuation is only known *after* the broken vs -//! non-broken status of the surrounding group is known: -//! -//! ``` -//! # struct Struct { x: u64, y: bool } -//! # let xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 0; -//! # let yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy = true; -//! # -//! let _ = Struct { x: 0, y: true }; -//! -//! let _ = Struct { -//! x: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, -//! y: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy, //<- trailing comma if the expression wrapped -//! }; -//! ``` -//! -//! The formatting of `match` expressions is another case; we want small arms on -//! the same line as the pattern, and big arms wrapped in a brace. The presence -//! of the brace punctuation, comma, and semicolon are all dependent on whether -//! the arm fits on the line: -//! -//! ``` -//! # struct Entry { nanos: u32 } -//! # let total_nanos = 0u64; -//! # let mut total_secs = 0u64; -//! # let tmp; -//! # let entry = Entry { nanos: 0 }; -//! # const NANOS_PER_SEC: u32 = 1_000_000_000; -//! # -//! match total_nanos.checked_add(entry.nanos as u64) { -//! Some(n) => tmp = n, //<- small arm, inline with comma -//! None => { -//! total_secs = total_secs -//! .checked_add(total_nanos / NANOS_PER_SEC as u64) -//! .expect("overflow in iter::sum over durations"); -//! } //<- big arm, needs brace added, and also semicolon^ -//! } -//! ``` -//! -//! The printing algorithm implementation in this crate accommodates all of -//! these situations with conditional punctuation tokens whose selection can be -//! deferred and populated after it's known that the group is or is not broken. - -#![allow( - clippy::cast_possible_wrap, - clippy::cast_sign_loss, - clippy::doc_markdown, - clippy::enum_glob_use, - clippy::items_after_statements, - clippy::match_like_matches_macro, - clippy::match_same_arms, - clippy::module_name_repetitions, - clippy::must_use_candidate, - clippy::needless_pass_by_value, - clippy::similar_names, - clippy::unused_self, - clippy::vec_init_then_push -)] -#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))] - -mod algorithm; -mod attr; -mod convenience; -mod data; -mod expr; -mod file; -mod generics; -mod item; -mod iter; -mod lifetime; -mod lit; -mod mac; -mod pat; -mod path; -mod ring; -mod stmt; -mod token; -mod ty; - -use algorithm::Printer; -use syn::{Expr, File}; - -// Target line width. -const MARGIN: isize = 89; - -// Number of spaces increment at each level of block indentation. -const INDENT: isize = 4; - -// Every line is allowed at least this much space, even if highly indented. -const MIN_SPACE: isize = 60; - -pub fn unparse(file: &File) -> String { - let mut p = Printer::new(); - p.file(file); - p.eof() -} - -pub fn unparse_expr(file: &Expr) -> String { - let mut p = Printer::new(); - p.expr(file); - p.eof() -} diff --git a/packages/autofmt/src/prettyplease/pat.rs b/packages/autofmt/src/prettyplease/pat.rs deleted file mode 100644 index 0ca86ef06..000000000 --- a/packages/autofmt/src/prettyplease/pat.rs +++ /dev/null @@ -1,210 +0,0 @@ -use super::algorithm::Printer; -use super::iter::IterDelimited; -use super::INDENT; -use proc_macro2::TokenStream; -use syn::{ - FieldPat, Pat, PatBox, PatIdent, PatLit, PatMacro, PatOr, PatPath, PatRange, PatReference, - PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild, RangeLimits, -}; - -impl Printer { - pub fn pat(&mut self, pat: &Pat) { - match pat { - Pat::Box(pat) => self.pat_box(pat), - Pat::Ident(pat) => self.pat_ident(pat), - Pat::Lit(pat) => self.pat_lit(pat), - Pat::Macro(pat) => self.pat_macro(pat), - Pat::Or(pat) => self.pat_or(pat), - Pat::Path(pat) => self.pat_path(pat), - Pat::Range(pat) => self.pat_range(pat), - Pat::Reference(pat) => self.pat_reference(pat), - Pat::Rest(pat) => self.pat_rest(pat), - Pat::Slice(pat) => self.pat_slice(pat), - Pat::Struct(pat) => self.pat_struct(pat), - Pat::Tuple(pat) => self.pat_tuple(pat), - Pat::TupleStruct(pat) => self.pat_tuple_struct(pat), - Pat::Type(pat) => self.pat_type(pat), - Pat::Verbatim(pat) => self.pat_verbatim(pat), - Pat::Wild(pat) => self.pat_wild(pat), - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => unimplemented!("unknown Pat"), - } - } - - fn pat_box(&mut self, pat: &PatBox) { - self.outer_attrs(&pat.attrs); - self.word("box "); - self.pat(&pat.pat); - } - - fn pat_ident(&mut self, pat: &PatIdent) { - self.outer_attrs(&pat.attrs); - if pat.by_ref.is_some() { - self.word("ref "); - } - if pat.mutability.is_some() { - self.word("mut "); - } - self.ident(&pat.ident); - if let Some((_at_token, subpat)) = &pat.subpat { - self.word(" @ "); - self.pat(subpat); - } - } - - fn pat_lit(&mut self, pat: &PatLit) { - self.outer_attrs(&pat.attrs); - self.expr(&pat.expr); - } - - fn pat_macro(&mut self, pat: &PatMacro) { - self.outer_attrs(&pat.attrs); - self.mac(&pat.mac, None); - } - - fn pat_or(&mut self, pat: &PatOr) { - self.outer_attrs(&pat.attrs); - let mut consistent_break = false; - for case in &pat.cases { - match case { - Pat::Lit(_) | Pat::Wild(_) => {} - _ => { - consistent_break = true; - break; - } - } - } - if consistent_break { - self.cbox(0); - } else { - self.ibox(0); - } - for case in pat.cases.iter().delimited() { - if !case.is_first { - self.space(); - self.word("| "); - } - self.pat(&case); - } - self.end(); - } - - fn pat_path(&mut self, pat: &PatPath) { - self.outer_attrs(&pat.attrs); - self.qpath(&pat.qself, &pat.path); - } - - fn pat_range(&mut self, pat: &PatRange) { - self.outer_attrs(&pat.attrs); - self.expr(&pat.lo); - match &pat.limits { - RangeLimits::HalfOpen(_) => self.word(".."), - RangeLimits::Closed(_) => self.word("..="), - } - self.expr(&pat.hi); - } - - fn pat_reference(&mut self, pat: &PatReference) { - self.outer_attrs(&pat.attrs); - self.word("&"); - if pat.mutability.is_some() { - self.word("mut "); - } - self.pat(&pat.pat); - } - - fn pat_rest(&mut self, pat: &PatRest) { - self.outer_attrs(&pat.attrs); - self.word(".."); - } - - fn pat_slice(&mut self, pat: &PatSlice) { - self.outer_attrs(&pat.attrs); - self.word("["); - for elem in pat.elems.iter().delimited() { - self.pat(&elem); - self.trailing_comma(elem.is_last); - } - self.word("]"); - } - - fn pat_struct(&mut self, pat: &PatStruct) { - self.outer_attrs(&pat.attrs); - self.cbox(INDENT); - self.path(&pat.path); - self.word(" {"); - self.space_if_nonempty(); - for field in pat.fields.iter().delimited() { - self.field_pat(&field); - self.trailing_comma_or_space(field.is_last && pat.dot2_token.is_none()); - } - if pat.dot2_token.is_some() { - self.word(".."); - self.space(); - } - self.offset(-INDENT); - self.end(); - self.word("}"); - } - - fn pat_tuple(&mut self, pat: &PatTuple) { - self.outer_attrs(&pat.attrs); - self.word("("); - self.cbox(INDENT); - self.zerobreak(); - for elem in pat.elems.iter().delimited() { - self.pat(&elem); - if pat.elems.len() == 1 { - if pat.elems.trailing_punct() { - self.word(","); - } - self.zerobreak(); - } else { - self.trailing_comma(elem.is_last); - } - } - self.offset(-INDENT); - self.end(); - self.word(")"); - } - - fn pat_tuple_struct(&mut self, pat: &PatTupleStruct) { - self.outer_attrs(&pat.attrs); - self.path(&pat.path); - self.word("("); - self.cbox(INDENT); - self.zerobreak(); - for elem in pat.pat.elems.iter().delimited() { - self.pat(&elem); - self.trailing_comma(elem.is_last); - } - self.offset(-INDENT); - self.end(); - self.word(")"); - } - - pub fn pat_type(&mut self, pat: &PatType) { - self.outer_attrs(&pat.attrs); - self.pat(&pat.pat); - self.word(": "); - self.ty(&pat.ty); - } - - fn pat_verbatim(&mut self, pat: &TokenStream) { - unimplemented!("Pat::Verbatim `{}`", pat); - } - - fn pat_wild(&mut self, pat: &PatWild) { - self.outer_attrs(&pat.attrs); - self.word("_"); - } - - fn field_pat(&mut self, field_pat: &FieldPat) { - self.outer_attrs(&field_pat.attrs); - if field_pat.colon_token.is_some() { - self.member(&field_pat.member); - self.word(": "); - } - self.pat(&field_pat.pat); - } -} diff --git a/packages/autofmt/src/prettyplease/path.rs b/packages/autofmt/src/prettyplease/path.rs deleted file mode 100644 index 460fe5cb7..000000000 --- a/packages/autofmt/src/prettyplease/path.rs +++ /dev/null @@ -1,181 +0,0 @@ -use super::algorithm::Printer; -use super::iter::IterDelimited; -use super::INDENT; -use syn::{ - AngleBracketedGenericArguments, Binding, Constraint, Expr, GenericArgument, - ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, -}; - -impl Printer { - pub fn path(&mut self, path: &Path) { - assert!(!path.segments.is_empty()); - for segment in path.segments.iter().delimited() { - if !segment.is_first || path.leading_colon.is_some() { - self.word("::"); - } - self.path_segment(&segment); - } - } - - pub fn path_segment(&mut self, segment: &PathSegment) { - self.ident(&segment.ident); - self.path_arguments(&segment.arguments); - } - - fn path_arguments(&mut self, arguments: &PathArguments) { - match arguments { - PathArguments::None => {} - PathArguments::AngleBracketed(arguments) => { - self.angle_bracketed_generic_arguments(arguments); - } - PathArguments::Parenthesized(arguments) => { - self.parenthesized_generic_arguments(arguments); - } - } - } - - fn generic_argument(&mut self, arg: &GenericArgument) { - match arg { - GenericArgument::Lifetime(lifetime) => self.lifetime(lifetime), - GenericArgument::Type(ty) => self.ty(ty), - GenericArgument::Binding(binding) => self.binding(binding), - GenericArgument::Constraint(constraint) => self.constraint(constraint), - GenericArgument::Const(expr) => { - match expr { - Expr::Lit(expr) => self.expr_lit(expr), - Expr::Block(expr) => self.expr_block(expr), - // ERROR CORRECTION: Add braces to make sure that the - // generated code is valid. - _ => { - self.word("{"); - self.expr(expr); - self.word("}"); - } - } - } - } - } - - fn angle_bracketed_generic_arguments(&mut self, generic: &AngleBracketedGenericArguments) { - if generic.colon2_token.is_some() { - self.word("::"); - } - self.word("<"); - self.cbox(INDENT); - self.zerobreak(); - - // Print lifetimes before types and consts, all before bindings, - // regardless of their order in self.args. - // - // TODO: ordering rules for const arguments vs type arguments have - // not been settled yet. https://github.com/rust-lang/rust/issues/44580 - for arg in generic.args.iter().delimited() { - match *arg { - GenericArgument::Lifetime(_) => { - self.generic_argument(&arg); - self.trailing_comma(arg.is_last); - } - GenericArgument::Type(_) - | GenericArgument::Binding(_) - | GenericArgument::Constraint(_) - | GenericArgument::Const(_) => {} - } - } - for arg in generic.args.iter().delimited() { - match *arg { - GenericArgument::Type(_) | GenericArgument::Const(_) => { - self.generic_argument(&arg); - self.trailing_comma(arg.is_last); - } - GenericArgument::Lifetime(_) - | GenericArgument::Binding(_) - | GenericArgument::Constraint(_) => {} - } - } - for arg in generic.args.iter().delimited() { - match *arg { - GenericArgument::Binding(_) | GenericArgument::Constraint(_) => { - self.generic_argument(&arg); - self.trailing_comma(arg.is_last); - } - GenericArgument::Lifetime(_) - | GenericArgument::Type(_) - | GenericArgument::Const(_) => {} - } - } - - self.offset(-INDENT); - self.end(); - self.word(">"); - } - - fn binding(&mut self, binding: &Binding) { - self.ident(&binding.ident); - self.word(" = "); - self.ty(&binding.ty); - } - - fn constraint(&mut self, constraint: &Constraint) { - self.ident(&constraint.ident); - self.ibox(INDENT); - for bound in constraint.bounds.iter().delimited() { - if bound.is_first { - self.word(": "); - } else { - self.space(); - self.word("+ "); - } - self.type_param_bound(&bound); - } - self.end(); - } - - fn parenthesized_generic_arguments(&mut self, arguments: &ParenthesizedGenericArguments) { - self.cbox(INDENT); - self.word("("); - self.zerobreak(); - for ty in arguments.inputs.iter().delimited() { - self.ty(&ty); - self.trailing_comma(ty.is_last); - } - self.offset(-INDENT); - self.word(")"); - self.return_type(&arguments.output); - self.end(); - } - - pub fn qpath(&mut self, qself: &Option, path: &Path) { - let qself = match qself { - Some(qself) => qself, - None => { - self.path(path); - return; - } - }; - - assert!(qself.position < path.segments.len()); - - self.word("<"); - self.ty(&qself.ty); - - let mut segments = path.segments.iter(); - if qself.position > 0 { - self.word(" as "); - for segment in segments.by_ref().take(qself.position).delimited() { - if !segment.is_first || path.leading_colon.is_some() { - self.word("::"); - } - self.path_segment(&segment); - if segment.is_last { - self.word(">"); - } - } - } else { - self.word(">"); - } - for segment in segments { - self.word("::"); - self.path_segment(segment); - } - } -} diff --git a/packages/autofmt/src/prettyplease/ring.rs b/packages/autofmt/src/prettyplease/ring.rs deleted file mode 100644 index aff92589a..000000000 --- a/packages/autofmt/src/prettyplease/ring.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::collections::VecDeque; -use std::ops::{Index, IndexMut}; - -pub struct RingBuffer { - data: VecDeque, - // Abstract index of data[0] in infinitely sized queue - offset: usize, -} - -impl RingBuffer { - pub fn new() -> Self { - RingBuffer { - data: VecDeque::new(), - offset: 0, - } - } - - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - pub fn len(&self) -> usize { - self.data.len() - } - - pub fn push(&mut self, value: T) -> usize { - let index = self.offset + self.data.len(); - self.data.push_back(value); - index - } - - pub fn clear(&mut self) { - self.data.clear(); - } - - pub fn index_of_first(&self) -> usize { - self.offset - } - - pub fn first(&self) -> &T { - &self.data[0] - } - - pub fn first_mut(&mut self) -> &mut T { - &mut self.data[0] - } - - pub fn pop_first(&mut self) -> T { - self.offset += 1; - self.data.pop_front().unwrap() - } - - pub fn last(&self) -> &T { - self.data.back().unwrap() - } - - pub fn last_mut(&mut self) -> &mut T { - self.data.back_mut().unwrap() - } - - pub fn second_last(&self) -> &T { - &self.data[self.data.len() - 2] - } - - pub fn pop_last(&mut self) { - self.data.pop_back().unwrap(); - } -} - -impl Index for RingBuffer { - type Output = T; - fn index(&self, index: usize) -> &Self::Output { - &self.data[index.checked_sub(self.offset).unwrap()] - } -} - -impl IndexMut for RingBuffer { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.data[index.checked_sub(self.offset).unwrap()] - } -} diff --git a/packages/autofmt/src/prettyplease/stmt.rs b/packages/autofmt/src/prettyplease/stmt.rs deleted file mode 100644 index 68295fa70..000000000 --- a/packages/autofmt/src/prettyplease/stmt.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::algorithm::Printer; -use syn::{Expr, Stmt}; - -impl Printer { - pub fn stmt(&mut self, stmt: &Stmt) { - match stmt { - Stmt::Local(local) => { - self.outer_attrs(&local.attrs); - self.ibox(0); - self.word("let "); - self.pat(&local.pat); - if let Some((_eq, init)) = &local.init { - self.word(" = "); - self.neverbreak(); - self.expr(init); - } - self.word(";"); - self.end(); - self.hardbreak(); - } - Stmt::Item(item) => self.item(item), - Stmt::Expr(expr) => { - if break_after(expr) { - self.ibox(0); - self.expr_beginning_of_line(expr, true); - if add_semi(expr) { - self.word(";"); - } - self.end(); - self.hardbreak(); - } else { - self.expr_beginning_of_line(expr, true); - } - } - Stmt::Semi(expr, _semi) => { - if let Expr::Verbatim(tokens) = expr { - if tokens.is_empty() { - return; - } - } - self.ibox(0); - self.expr_beginning_of_line(expr, true); - if !remove_semi(expr) { - self.word(";"); - } - self.end(); - self.hardbreak(); - } - } - } -} - -pub fn add_semi(expr: &Expr) -> bool { - match expr { - Expr::Assign(_) - | Expr::AssignOp(_) - | Expr::Break(_) - | Expr::Continue(_) - | Expr::Return(_) - | Expr::Yield(_) => true, - Expr::Group(group) => add_semi(&group.expr), - _ => false, - } -} - -pub fn break_after(expr: &Expr) -> bool { - if let Expr::Group(group) = expr { - if let Expr::Verbatim(verbatim) = group.expr.as_ref() { - return !verbatim.is_empty(); - } - } - true -} - -fn remove_semi(expr: &Expr) -> bool { - match expr { - Expr::ForLoop(_) | Expr::While(_) => true, - Expr::Group(group) => remove_semi(&group.expr), - Expr::If(expr) => match &expr.else_branch { - Some((_else_token, else_branch)) => remove_semi(else_branch), - None => true, - }, - _ => false, - } -} diff --git a/packages/autofmt/src/prettyplease/token.rs b/packages/autofmt/src/prettyplease/token.rs deleted file mode 100644 index f25f0d3c8..000000000 --- a/packages/autofmt/src/prettyplease/token.rs +++ /dev/null @@ -1,80 +0,0 @@ -use super::algorithm::Printer; -use proc_macro2::{Delimiter, Ident, Literal, Spacing, TokenStream, TokenTree}; - -impl Printer { - pub fn single_token(&mut self, token: Token, group_contents: fn(&mut Self, TokenStream)) { - match token { - Token::Group(delimiter, stream) => self.token_group(delimiter, stream, group_contents), - Token::Ident(ident) => self.ident(&ident), - Token::Punct(ch, _spacing) => self.token_punct(ch), - Token::Literal(literal) => self.token_literal(&literal), - } - } - - fn token_group( - &mut self, - delimiter: Delimiter, - stream: TokenStream, - group_contents: fn(&mut Self, TokenStream), - ) { - self.delimiter_open(delimiter); - if !stream.is_empty() { - if delimiter == Delimiter::Brace { - self.space(); - } - group_contents(self, stream); - if delimiter == Delimiter::Brace { - self.space(); - } - } - self.delimiter_close(delimiter); - } - - pub fn ident(&mut self, ident: &Ident) { - self.word(ident.to_string()); - } - - pub fn token_punct(&mut self, ch: char) { - self.word(ch.to_string()); - } - - pub fn token_literal(&mut self, literal: &Literal) { - self.word(literal.to_string()); - } - - pub fn delimiter_open(&mut self, delimiter: Delimiter) { - self.word(match delimiter { - Delimiter::Parenthesis => "(", - Delimiter::Brace => "{", - Delimiter::Bracket => "[", - Delimiter::None => return, - }); - } - - pub fn delimiter_close(&mut self, delimiter: Delimiter) { - self.word(match delimiter { - Delimiter::Parenthesis => ")", - Delimiter::Brace => "}", - Delimiter::Bracket => "]", - Delimiter::None => return, - }); - } -} - -pub enum Token { - Group(Delimiter, TokenStream), - Ident(Ident), - Punct(char, Spacing), - Literal(Literal), -} - -impl From for Token { - fn from(tt: TokenTree) -> Self { - match tt { - TokenTree::Group(group) => Token::Group(group.delimiter(), group.stream()), - TokenTree::Ident(ident) => Token::Ident(ident), - TokenTree::Punct(punct) => Token::Punct(punct.as_char(), punct.spacing()), - TokenTree::Literal(literal) => Token::Literal(literal), - } - } -} diff --git a/packages/autofmt/src/prettyplease/ty.rs b/packages/autofmt/src/prettyplease/ty.rs deleted file mode 100644 index 93cb48c77..000000000 --- a/packages/autofmt/src/prettyplease/ty.rs +++ /dev/null @@ -1,202 +0,0 @@ -use super::algorithm::Printer; -use super::iter::IterDelimited; -use super::INDENT; -use proc_macro2::TokenStream; -use syn::{ - Abi, BareFnArg, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer, - TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, - TypeTuple, Variadic, -}; - -impl Printer { - pub fn ty(&mut self, ty: &Type) { - match ty { - Type::Array(ty) => self.type_array(ty), - Type::BareFn(ty) => self.type_bare_fn(ty), - Type::Group(ty) => self.type_group(ty), - Type::ImplTrait(ty) => self.type_impl_trait(ty), - Type::Infer(ty) => self.type_infer(ty), - Type::Macro(ty) => self.type_macro(ty), - Type::Never(ty) => self.type_never(ty), - Type::Paren(ty) => self.type_paren(ty), - Type::Path(ty) => self.type_path(ty), - Type::Ptr(ty) => self.type_ptr(ty), - Type::Reference(ty) => self.type_reference(ty), - Type::Slice(ty) => self.type_slice(ty), - Type::TraitObject(ty) => self.type_trait_object(ty), - Type::Tuple(ty) => self.type_tuple(ty), - Type::Verbatim(ty) => self.type_verbatim(ty), - #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] - _ => unimplemented!("unknown Type"), - } - } - - fn type_array(&mut self, ty: &TypeArray) { - self.word("["); - self.ty(&ty.elem); - self.word("; "); - self.expr(&ty.len); - self.word("]"); - } - - fn type_bare_fn(&mut self, ty: &TypeBareFn) { - if let Some(bound_lifetimes) = &ty.lifetimes { - self.bound_lifetimes(bound_lifetimes); - } - if ty.unsafety.is_some() { - self.word("unsafe "); - } - if let Some(abi) = &ty.abi { - self.abi(abi); - } - self.word("fn("); - self.cbox(INDENT); - self.zerobreak(); - for bare_fn_arg in ty.inputs.iter().delimited() { - self.bare_fn_arg(&bare_fn_arg); - self.trailing_comma(bare_fn_arg.is_last && ty.variadic.is_none()); - } - if let Some(variadic) = &ty.variadic { - self.variadic(variadic); - self.zerobreak(); - } - self.offset(-INDENT); - self.end(); - self.word(")"); - self.return_type(&ty.output); - } - - fn type_group(&mut self, ty: &TypeGroup) { - self.ty(&ty.elem); - } - - fn type_impl_trait(&mut self, ty: &TypeImplTrait) { - self.word("impl "); - for type_param_bound in ty.bounds.iter().delimited() { - if !type_param_bound.is_first { - self.word(" + "); - } - self.type_param_bound(&type_param_bound); - } - } - - fn type_infer(&mut self, ty: &TypeInfer) { - let _ = ty; - self.word("_"); - } - - fn type_macro(&mut self, ty: &TypeMacro) { - self.mac(&ty.mac, None); - } - - fn type_never(&mut self, ty: &TypeNever) { - let _ = ty; - self.word("!"); - } - - fn type_paren(&mut self, ty: &TypeParen) { - self.word("("); - self.ty(&ty.elem); - self.word(")"); - } - - fn type_path(&mut self, ty: &TypePath) { - self.qpath(&ty.qself, &ty.path); - } - - fn type_ptr(&mut self, ty: &TypePtr) { - self.word("*"); - if ty.mutability.is_some() { - self.word("mut "); - } else { - self.word("const "); - } - self.ty(&ty.elem); - } - - fn type_reference(&mut self, ty: &TypeReference) { - self.word("&"); - if let Some(lifetime) = &ty.lifetime { - self.lifetime(lifetime); - self.nbsp(); - } - if ty.mutability.is_some() { - self.word("mut "); - } - self.ty(&ty.elem); - } - - fn type_slice(&mut self, ty: &TypeSlice) { - self.word("["); - self.ty(&ty.elem); - self.word("]"); - } - - fn type_trait_object(&mut self, ty: &TypeTraitObject) { - self.word("dyn "); - for type_param_bound in ty.bounds.iter().delimited() { - if !type_param_bound.is_first { - self.word(" + "); - } - self.type_param_bound(&type_param_bound); - } - } - - fn type_tuple(&mut self, ty: &TypeTuple) { - self.word("("); - self.cbox(INDENT); - self.zerobreak(); - for elem in ty.elems.iter().delimited() { - self.ty(&elem); - if ty.elems.len() == 1 { - self.word(","); - self.zerobreak(); - } else { - self.trailing_comma(elem.is_last); - } - } - self.offset(-INDENT); - self.end(); - self.word(")"); - } - - fn type_verbatim(&mut self, ty: &TokenStream) { - if ty.to_string() == "..." { - self.word("..."); - } else { - unimplemented!("Type::Verbatim `{}`", ty); - } - } - - pub fn return_type(&mut self, ty: &ReturnType) { - match ty { - ReturnType::Default => {} - ReturnType::Type(_arrow, ty) => { - self.word(" -> "); - self.ty(ty); - } - } - } - - fn bare_fn_arg(&mut self, bare_fn_arg: &BareFnArg) { - self.outer_attrs(&bare_fn_arg.attrs); - if let Some((name, _colon)) = &bare_fn_arg.name { - self.ident(name); - self.word(": "); - } - self.ty(&bare_fn_arg.ty); - } - - fn variadic(&mut self, variadic: &Variadic) { - self.outer_attrs(&variadic.attrs); - self.word("..."); - } - - pub fn abi(&mut self, abi: &Abi) { - self.word("extern "); - if let Some(name) = &abi.name { - self.lit_str(name); - self.nbsp(); - } - } -} diff --git a/packages/autofmt/src/util.rs b/packages/autofmt/src/util.rs new file mode 100644 index 000000000..2cf362db7 --- /dev/null +++ b/packages/autofmt/src/util.rs @@ -0,0 +1,43 @@ +use dioxus_rsx::*; +use std::fmt::Write; + +pub fn extract_attr_len(attributes: &[ElementAttrNamed]) -> usize { + attributes + .iter() + .map(|attr| match &attr.attr { + ElementAttr::AttrText { name, value } => value.value().len(), + ElementAttr::AttrExpression { name, value } => 10, + ElementAttr::CustomAttrText { name, value } => value.value().len(), + ElementAttr::CustomAttrExpression { name, value } => 10, + ElementAttr::EventTokens { name, tokens } => 1000000, + }) + .sum::() +} + +pub fn write_tabs(f: &mut dyn Write, num: usize) -> std::fmt::Result { + for _ in 0..num { + write!(f, " ")? + } + Ok(()) +} + +pub fn find_bracket_end(contents: &str) -> Option { + let mut depth = 0; + let mut i = 0; + + for c in contents.chars() { + if c == '{' { + depth += 1; + } else if c == '}' { + depth -= 1; + } + + if depth == 0 { + return Some(i); + } + + i += 1; + } + + None +} diff --git a/packages/autofmt/tests/sink.rs b/packages/autofmt/tests/sink.rs index 736abc7dc..3f4df0a4e 100644 --- a/packages/autofmt/tests/sink.rs +++ b/packages/autofmt/tests/sink.rs @@ -36,6 +36,10 @@ fn formats_block() { class: "asd", } } + + Component {} + + Component {} } } "#; diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index 56d82876f..0cdae3bcb 100644 --- a/packages/core-macro/src/lib.rs +++ b/packages/core-macro/src/lib.rs @@ -66,6 +66,7 @@ pub fn rsx(s: TokenStream) -> TokenStream { Err(err) => err.into_compile_error().into(), } } + #[cfg(not(feature = "hot_reload"))] body.to_token_stream().into() }