Skip to content

Commit

Permalink
feat(format/html): implement bracketSameLine
Browse files Browse the repository at this point in the history
  • Loading branch information
dyc3 committed Jan 27, 2025
1 parent d400d69 commit 8afc1a8
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 38 deletions.
50 changes: 42 additions & 8 deletions crates/biome_html_formatter/src/html/auxiliary/opening_element.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::prelude::*;
use biome_formatter::{write, FormatRuleWithOptions};
use biome_formatter::{write, AttributePosition, FormatRuleWithOptions};
use biome_html_syntax::{HtmlOpeningElement, HtmlOpeningElementFields};
#[derive(Debug, Clone, Default)]
pub(crate) struct FormatHtmlOpeningElement {
Expand Down Expand Up @@ -36,14 +36,48 @@ impl FormatNodeRule<HtmlOpeningElement> for FormatHtmlOpeningElement {
r_angle_token,
} = node.as_fields();

let bracket_same_line = f.options().bracket_same_line().value();
write!(f, [l_angle_token.format(), name.format()])?;
if attributes.len() > 0 {
write!(f, [space(), attributes.format()])?
}
// When these tokens are borrowed, they are managed by the sibling `HtmlElementList` formatter.
if !self.r_angle_is_borrowed {
write!(f, [r_angle_token.format()])?;
}
let line_break = if f.options().attribute_position() == AttributePosition::Multiline {
hard_line_break()
} else {
soft_line_break_or_space()
};

let attr_group_id = f.group_id("element-attr-group-id");
write!(
f,
[&group(&format_with(|f| {
if attributes.len() > 0 {
write!(
f,
[
space(),
&soft_line_indent_or_space(&format_with(|f| {
f.join_with(&line_break)
.entries(attributes.iter().formatted())
.finish()?;

Ok(())
}))
]
)?;
}
// Whitespace sensitivity takes precedence over bracketSameLine for correctness.
//
// The r_angle is placed inside this group because prettier always includes this token
// in the same group as the attributes, unless the token is being borrowed.
// When these tokens are borrowed, they are managed by the sibling `HtmlElementList` formatter.
if !bracket_same_line {
write!(f, [soft_line_break()])?;
}
if !self.r_angle_is_borrowed {
write!(f, [r_angle_token.format()])?;
}
Ok(())
}))
.with_group_id(Some(attr_group_id))]
)?;

Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::prelude::*;
use biome_formatter::write;
use biome_formatter::{write, AttributePosition};
use biome_html_syntax::{HtmlSelfClosingElement, HtmlSelfClosingElementFields};
#[derive(Debug, Clone, Default)]
pub(crate) struct FormatHtmlSelfClosingElement;
Expand All @@ -12,24 +12,58 @@ impl FormatNodeRule<HtmlSelfClosingElement> for FormatHtmlSelfClosingElement {
slash_token,
r_angle_token,
} = node.as_fields();
let bracket_same_line = f.options().bracket_same_line().value();

write!(f, [l_angle_token.format(), name.format(), space()])?;
let line_break = if f.options().attribute_position() == AttributePosition::Multiline {
hard_line_break()
} else {
soft_line_break_or_space()
};

let attr_group_id = f.group_id("element-attr-group-id");
write!(
f,
[
l_angle_token.format(),
name.format(),
space(),
attributes.format(),
space(),
]
)?;
[&group(&format_with(|f| {
if attributes.len() > 0 {
write!(
f,
[
space(),
&soft_line_indent_or_space(&format_with(|f| {
f.join_with(&line_break)
.entries(attributes.iter().formatted())
.finish()?;

if slash_token.is_some() {
write!(f, [slash_token.format()])?;
} else {
write!(f, [text("/")])?;
}
Ok(())
}))
]
)?;
}
// Whitespace sensitivity takes precedence over bracketSameLine for correctness.
//
// The r_angle is placed inside this group because prettier always includes this token
// in the same group as the attributes, unless the token is being borrowed.
// When these tokens are borrowed, they are managed by the sibling `HtmlElementList` formatter.
if bracket_same_line {
write!(f, [hard_space()])?;
} else {
write!(f, [soft_line_break_or_space()])?;
}

// TODO: These tokens (the `/>`) are not yet borrowed by sibling elements for whitespace sensitivity.
if slash_token.is_some() {
write!(f, [slash_token.format()])?;
} else {
write!(f, [text("/")])?;
}

write!(f, [r_angle_token.format()])?;
Ok(())
}))
.with_group_id(Some(attr_group_id))]
)?;

write!(f, [r_angle_token.format()])
Ok(())
}
}
20 changes: 5 additions & 15 deletions crates/biome_html_formatter/src/html/lists/attribute_list.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
use crate::prelude::*;
use biome_formatter::{write, AttributePosition};
use biome_html_syntax::HtmlAttributeList;
#[derive(Debug, Clone, Default)]
pub(crate) struct FormatHtmlAttributeList;
impl FormatRule<HtmlAttributeList> for FormatHtmlAttributeList {
type Context = HtmlFormatContext;
fn fmt(&self, node: &HtmlAttributeList, f: &mut HtmlFormatter) -> FormatResult<()> {
let line_break = if f.options().attribute_position() == AttributePosition::Multiline {
hard_line_break()
} else {
soft_line_break_or_space()
};

write!(
f,
[&group(&soft_block_indent(&format_with(|f| {
f.join_with(&line_break)
.entries(node.iter().formatted())
.finish()
})))]
)
// The formatting of this node is handled by `HtmlOpeningElement` and `HtmlSelfClosingElement` instead.
//
// This is because whether or not the element children breaks is partially dependent whether or not the
// attributes break, and to be able to handle the `bracketSameLine` option correctly.
format_verbatim_node(node.syntax()).fmt(f)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div
id="hello"
class="world really-long-class-name another-really-long-class-name"
style="color: red"
data-foo="bar"
data-bar="foo"
>
hello world
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
source: crates/biome_formatter_test/src/snapshot_builder.rs
info: elements/bracket-same-line/element.html
---
# Input

```html
<div
id="hello"
class="world really-long-class-name another-really-long-class-name"
style="color: red"
data-foo="bar"
data-bar="foo"
>
hello world
</div>
```


=============================

# Outputs

## Output 1

-----
Indent style: Tab
Indent width: 2
Line ending: LF
Line width: 80
Attribute Position: Auto
Bracket same line: false
Whitespace sensitivity: strict
Indent script and style: false
-----

```html
<div
id="hello"
class="world really-long-class-name another-really-long-class-name"
style="color: red"
data-foo="bar"
data-bar="foo"
>hello world</div>
```

## Output 1

-----
Indent style: Tab
Indent width: 2
Line ending: LF
Line width: 80
Attribute Position: Auto
Bracket same line: true
Whitespace sensitivity: strict
Indent script and style: false
-----

```html
<div
id="hello"
class="world really-long-class-name another-really-long-class-name"
style="color: red"
data-foo="bar"
data-bar="foo">hello world</div>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "../../../../../../../../packages/@biomejs/biome/configuration_schema.json",
"formatter": {
"bracketSameLine": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<selfclosing
id="hello"
class="world"
style="color: red"
data-foo="bar"
data-bar="foo"
/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
source: crates/biome_formatter_test/src/snapshot_builder.rs
info: elements/bracket-same-line/self-closing.html
---
# Input

```html
<selfclosing
id="hello"
class="world"
style="color: red"
data-foo="bar"
data-bar="foo"
/>
```


=============================

# Outputs

## Output 1

-----
Indent style: Tab
Indent width: 2
Line ending: LF
Line width: 80
Attribute Position: Auto
Bracket same line: false
Whitespace sensitivity: strict
Indent script and style: false
-----

```html
<selfclosing
id="hello"
class="world"
style="color: red"
data-foo="bar"
data-bar="foo"
/>
```

## Output 1

-----
Indent style: Tab
Indent width: 2
Line ending: LF
Line width: 80
Attribute Position: Auto
Bracket same line: true
Whitespace sensitivity: strict
Indent script and style: false
-----

```html
<selfclosing
id="hello"
class="world"
style="color: red"
data-foo="bar"
data-bar="foo" />
```

0 comments on commit 8afc1a8

Please sign in to comment.