Skip to content

Commit e21f128

Browse files
committed
feat: support keeping labels and env instructions on the same line
1 parent f5977da commit e21f128

File tree

4 files changed

+82
-21
lines changed

4 files changed

+82
-21
lines changed

src/parser/context.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::collections::HashSet;
22
use std::rc::Rc;
33

4+
use dockerfile_parser::Dockerfile;
45
use dockerfile_parser::Span;
56

67
use super::helpers::parse_comments;
@@ -9,6 +10,7 @@ use crate::configuration::Configuration;
910

1011
pub struct Context<'a> {
1112
pub config: &'a Configuration,
13+
pub dockerfile: &'a Dockerfile,
1214
pub text: &'a str,
1315
pub handled_comments: HashSet<usize>,
1416
current_node: Option<Node<'a>>,
@@ -17,10 +19,11 @@ pub struct Context<'a> {
1719
}
1820

1921
impl<'a> Context<'a> {
20-
pub fn new(text: &'a str, config: &'a Configuration) -> Self {
22+
pub fn new(text: &'a str, dockerfile: &'a Dockerfile, config: &'a Configuration) -> Self {
2123
Self {
2224
config,
2325
text,
26+
dockerfile,
2427
handled_comments: HashSet::new(),
2528
current_node: None,
2629
parent_stack: Vec::new(),

src/parser/parse.rs

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use super::helpers::*;
77
use crate::configuration::Configuration;
88

99
pub fn parse_items(file: &Dockerfile, text: &str, config: &Configuration) -> PrintItems {
10-
let mut context = Context::new(text, config);
10+
let mut context = Context::new(text, file, config);
1111
let mut items = PrintItems::new();
1212
let top_level_nodes = context.parse_nodes_with_comments(0, text.len(), file.instructions.iter().map(|i| i.into()));
1313

@@ -158,23 +158,61 @@ fn parse_label<'a>(node: &'a Label, context: &mut Context<'a>) -> PrintItems {
158158
}
159159

160160
fn parse_multi_line_items<'a>(nodes: Vec<Node<'a>>, indent_width: u32, context: &mut Context<'a>) -> PrintItems {
161-
let mut items = PrintItems::new();
162161
let count = nodes.len();
163-
for (i, node) in nodes.into_iter().enumerate() {
164-
let is_comment = node.is_comment();
165-
let mut node_items = parse_node(node, context);
166-
if i < count - 1 && !is_comment {
167-
node_items.push_str(" \\");
168-
node_items.push_signal(Signal::NewLine);
169-
}
170-
171-
if i > 0 {
172-
items.extend(parser_helpers::with_indent_times(node_items, indent_width));
173-
} else {
174-
items.extend(node_items);
175-
}
176-
}
177-
items
162+
let nodes_with_line_index = nodes
163+
.into_iter()
164+
.map(|node| {
165+
let (line_index, _) = node.span().relative_span(context.dockerfile);
166+
(node, line_index)
167+
})
168+
.collect::<Vec<_>>();
169+
let force_use_new_lines = nodes_with_line_index.len() > 1 && nodes_with_line_index[0].1 < nodes_with_line_index[1].1;
170+
171+
parser_helpers::parse_separated_values(
172+
|is_multiline| {
173+
nodes_with_line_index
174+
.into_iter()
175+
.enumerate()
176+
.map(|(i, (node, line_index))| {
177+
let is_comment = node.is_comment();
178+
let mut node_items = parse_node(node, context);
179+
if i < count - 1 && !is_comment {
180+
node_items.push_condition(conditions::if_true("endLineText", is_multiline.create_resolver(), {
181+
let mut items = PrintItems::new();
182+
items.push_str(" \\");
183+
items
184+
}));
185+
}
186+
187+
parser_helpers::ParsedValue {
188+
items: if i > 0 {
189+
parser_helpers::with_indent_times(node_items, indent_width)
190+
} else {
191+
node_items
192+
},
193+
lines_span: Some(parser_helpers::LinesSpan {
194+
start_line: line_index,
195+
end_line: line_index,
196+
}),
197+
allow_inline_multi_line: false,
198+
allow_inline_single_line: false,
199+
}
200+
})
201+
.collect()
202+
},
203+
parser_helpers::ParseSeparatedValuesOptions {
204+
prefer_hanging: false,
205+
force_use_new_lines,
206+
allow_blank_lines: false,
207+
single_line_space_at_start: false,
208+
single_line_space_at_end: false,
209+
single_line_separator: Signal::SpaceOrNewLine.into(),
210+
indent_width: 0 as u8,
211+
multi_line_options: parser_helpers::MultiLineOptions::same_line_no_indent(),
212+
force_possible_newline_at_start: false,
213+
},
214+
)
215+
.items
178216
}
179217

180218
fn parse_misc_instruction<'a>(node: &'a MiscInstruction, context: &mut Context<'a>) -> PrintItems {

tests/specs/Env/Env_All.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
~~ lineWidth: 50 ~~
12
== should format ==
23
ENV MY_NAME="John Doe"
3-
ENV MY_CAT=fluffy
4+
ENV MY_CAT=fluffy Test=asdf
45
ENV MY_NAME="John Doe" MY_DOG=RexTheDog \
56
MY_CAT=fluffy
67

78
[expect]
89
ENV MY_NAME="John Doe"
9-
ENV MY_CAT=fluffy
10+
ENV MY_CAT=fluffy Test=asdf
1011
ENV MY_NAME="John Doe" \
1112
MY_DOG=RexTheDog \
1213
MY_CAT=fluffy

tests/specs/Label/Label_All.txt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
1-
== should format multiple labels on multiple lines ==
1+
~~ lineWidth: 50 ~~
2+
== should format a single label ==
3+
LABEL some.label="value1"
4+
LABEL some.label2="with some text that goes over limit"
5+
6+
[expect]
7+
LABEL some.label="value1"
8+
LABEL some.label2="with some text that goes over limit"
9+
10+
== should format multiple labels on multiple lines when exceeding width ==
11+
LABEL multi="value1" label="value2"
212
LABEL multi.label="value1" multi.label2="value2" other="value3"
313

414
[expect]
15+
LABEL multi="value1" label="value2"
516
LABEL multi.label="value1" \
617
multi.label2="value2" \
718
other="value3"
819

20+
== should keep on multiple lines when could collapse ==
21+
LABEL multi="value1" \
22+
label="value2"
23+
24+
[expect]
25+
LABEL multi="value1" \
26+
label="value2"
27+
928
== should format with quotes ==
1029
LABEL "com.example.vendor"="ACME Incorporated"
1130

0 commit comments

Comments
 (0)