-
Notifications
You must be signed in to change notification settings - Fork 223
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: implement import formatting (#4248)
# Description chore: implement import formatting ## Additional Context #3945 (comment) ## Documentation Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. Co-authored-by: kevaundray <kevtheappdev@gmail.com> Co-authored-by: jfecher <jake@aztecprotocol.com>
- Loading branch information
1 parent
158c8ce
commit a8ffe0f
Showing
10 changed files
with
267 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
use noirc_frontend::macros_api::Span; | ||
|
||
use crate::{ | ||
utils::{comment_len, find_comment_end}, | ||
visitor::{FmtVisitor, Shape}, | ||
}; | ||
|
||
#[derive(Debug)] | ||
pub(crate) struct Item { | ||
pub(crate) leading: String, | ||
pub(crate) value: String, | ||
pub(crate) trailing: String, | ||
pub(crate) different_line: bool, | ||
} | ||
|
||
impl Item { | ||
pub(crate) fn total_width(&self) -> usize { | ||
comment_len(&self.leading) + self.value.chars().count() + comment_len(&self.trailing) | ||
} | ||
|
||
pub(crate) fn is_multiline(&self) -> bool { | ||
self.leading.contains('\n') || self.trailing.contains('\n') | ||
} | ||
} | ||
|
||
pub(crate) struct Items<'me, T> { | ||
visitor: &'me FmtVisitor<'me>, | ||
shape: Shape, | ||
elements: std::iter::Peekable<std::vec::IntoIter<T>>, | ||
last_position: u32, | ||
end_position: u32, | ||
} | ||
|
||
impl<'me, T: HasItem> Items<'me, T> { | ||
pub(crate) fn new( | ||
visitor: &'me FmtVisitor<'me>, | ||
shape: Shape, | ||
span: Span, | ||
elements: Vec<T>, | ||
) -> Self { | ||
Self { | ||
visitor, | ||
shape, | ||
last_position: span.start() + 1, | ||
end_position: span.end() - 1, | ||
elements: elements.into_iter().peekable(), | ||
} | ||
} | ||
} | ||
|
||
impl<T: HasItem> Iterator for Items<'_, T> { | ||
type Item = Item; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
let element = self.elements.next()?; | ||
let element_span = element.span(); | ||
|
||
let start = self.last_position; | ||
let end = element_span.start(); | ||
|
||
let is_last = self.elements.peek().is_none(); | ||
let next_start = self.elements.peek().map_or(self.end_position, |expr| expr.start()); | ||
|
||
let (leading, different_line) = self.leading(start, end); | ||
let expr = element.format(self.visitor, self.shape); | ||
let trailing = self.trailing(element_span.end(), next_start, is_last); | ||
|
||
Item { leading, value: expr, trailing, different_line }.into() | ||
} | ||
} | ||
|
||
impl<'me, T> Items<'me, T> { | ||
pub(crate) fn leading(&mut self, start: u32, end: u32) -> (String, bool) { | ||
let mut different_line = false; | ||
|
||
let leading = self.visitor.slice(start..end); | ||
let leading_trimmed = leading.trim(); | ||
|
||
let starts_with_block_comment = leading_trimmed.starts_with("/*"); | ||
let ends_with_block_comment = leading_trimmed.ends_with("*/"); | ||
let starts_with_single_line_comment = leading_trimmed.starts_with("//"); | ||
|
||
if ends_with_block_comment { | ||
let comment_end = leading_trimmed.rfind(|c| c == '/').unwrap(); | ||
|
||
if leading[comment_end..].contains('\n') { | ||
different_line = true; | ||
} | ||
} else if starts_with_single_line_comment || starts_with_block_comment { | ||
different_line = true; | ||
}; | ||
|
||
(leading_trimmed.to_string(), different_line) | ||
} | ||
|
||
pub(crate) fn trailing(&mut self, start: u32, end: u32, is_last: bool) -> String { | ||
let slice = self.visitor.slice(start..end); | ||
let comment_end = find_comment_end(slice, is_last); | ||
let trailing = slice[..comment_end].trim_matches(',').trim(); | ||
self.last_position = start + (comment_end as u32); | ||
trailing.to_string() | ||
} | ||
} | ||
|
||
pub(crate) trait HasItem { | ||
fn span(&self) -> Span; | ||
|
||
fn format(self, visitor: &FmtVisitor, shape: Shape) -> String; | ||
|
||
fn start(&self) -> u32 { | ||
self.span().start() | ||
} | ||
|
||
fn end(&self) -> u32 { | ||
self.span().end() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
mod array; | ||
mod expr; | ||
mod imports; | ||
mod infix; | ||
mod parenthesized; | ||
mod typ; | ||
|
||
pub(crate) use array::rewrite as array; | ||
pub(crate) use expr::{rewrite as expr, rewrite_sub_expr as sub_expr}; | ||
pub(crate) use imports::UseTree; | ||
pub(crate) use infix::rewrite as infix; | ||
pub(crate) use parenthesized::rewrite as parenthesized; | ||
pub(crate) use typ::rewrite as typ; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
use noirc_frontend::{PathKind, UseTreeKind}; | ||
|
||
use crate::{ | ||
items::Item, | ||
visitor::{ | ||
expr::{format_exprs, Tactic}, | ||
FmtVisitor, Shape, | ||
}, | ||
}; | ||
|
||
#[derive(Debug)] | ||
pub(crate) enum UseSegment { | ||
Ident(String, Option<String>), | ||
List(Vec<UseTree>), | ||
Dep, | ||
Crate, | ||
} | ||
|
||
impl UseSegment { | ||
fn rewrite(&self, visitor: &FmtVisitor, shape: Shape) -> String { | ||
match self { | ||
UseSegment::Ident(ident, None) => ident.clone(), | ||
UseSegment::Ident(ident, Some(rename)) => format!("{ident} as {rename}"), | ||
UseSegment::List(use_tree_list) => { | ||
let mut nested_shape = shape; | ||
nested_shape.indent.block_indent(visitor.config); | ||
|
||
let items: Vec<_> = use_tree_list | ||
.iter() | ||
.map(|item| Item { | ||
leading: String::new(), | ||
value: item.rewrite(visitor, shape).clone(), | ||
trailing: String::new(), | ||
different_line: false, | ||
}) | ||
.collect(); | ||
|
||
let list_str = | ||
format_exprs(visitor.config, Tactic::Mixed, false, items, nested_shape, true); | ||
|
||
if list_str.contains('\n') { | ||
format!( | ||
"{{\n{}{list_str}\n{}}}", | ||
nested_shape.indent.to_string(), | ||
shape.indent.to_string() | ||
) | ||
} else { | ||
format!("{{{list_str}}}") | ||
} | ||
} | ||
UseSegment::Dep => "dep".into(), | ||
UseSegment::Crate => "crate".into(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub(crate) struct UseTree { | ||
path: Vec<UseSegment>, | ||
} | ||
|
||
impl UseTree { | ||
pub(crate) fn from_ast(use_tree: noirc_frontend::UseTree) -> Self { | ||
let mut result = UseTree { path: vec![] }; | ||
|
||
match use_tree.prefix.kind { | ||
PathKind::Crate => result.path.push(UseSegment::Crate), | ||
PathKind::Dep => result.path.push(UseSegment::Dep), | ||
PathKind::Plain => {} | ||
}; | ||
|
||
result.path.extend( | ||
use_tree | ||
.prefix | ||
.segments | ||
.into_iter() | ||
.map(|segment| UseSegment::Ident(segment.to_string(), None)), | ||
); | ||
|
||
match use_tree.kind { | ||
UseTreeKind::Path(name, alias) => { | ||
result.path.push(UseSegment::Ident( | ||
name.to_string(), | ||
alias.map(|rename| rename.to_string()), | ||
)); | ||
} | ||
UseTreeKind::List(list) => { | ||
let segment = UseSegment::List(list.into_iter().map(UseTree::from_ast).collect()); | ||
result.path.push(segment); | ||
} | ||
} | ||
|
||
result | ||
} | ||
|
||
pub(crate) fn rewrite_top_level(&self, visitor: &FmtVisitor, shape: Shape) -> String { | ||
format!("use {};", self.rewrite(visitor, shape)) | ||
} | ||
|
||
fn rewrite(&self, visitor: &FmtVisitor, shape: Shape) -> String { | ||
let mut result = String::new(); | ||
|
||
let mut iter = self.path.iter().peekable(); | ||
while let Some(segment) = iter.next() { | ||
let segment_str = segment.rewrite(visitor, shape); | ||
result.push_str(&segment_str); | ||
|
||
if iter.peek().is_some() { | ||
result.push_str("::"); | ||
} | ||
} | ||
|
||
result | ||
} | ||
} |
Oops, something went wrong.