Skip to content

Commit 6b51e49

Browse files
authored
Merge pull request #39 from olehermanse/formatting
Implemented formatting according to the tests
2 parents edc31ce + ab91666 commit 6b51e49

3 files changed

Lines changed: 92 additions & 15 deletions

File tree

src/cfengine_cli/format.py

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ def stringify_children(children):
6060
result += " "
6161
if previous and previous.type == "=>":
6262
result += " "
63-
if previous and previous.type == "{":
64-
result += " "
65-
if previous and child.type == "}":
66-
result += " "
6763
result += string
6864
previous = child
6965
return result
@@ -75,8 +71,11 @@ def stringify_single_line(node):
7571
return stringify_children(node.children)
7672

7773

78-
def split_generic_value(node, indent):
79-
# TODO
74+
def split_generic_value(node, indent, line_length):
75+
if node.type == "call":
76+
return split_rval_call(node, indent, line_length)
77+
if node.type == "list":
78+
return split_rval_list(node, indent, line_length)
8079
return [stringify_single_line(node)]
8180

8281

@@ -90,7 +89,7 @@ def split_generic_list(middle, indent, line_length):
9089
if len(line) < line_length:
9190
elements.append(line)
9291
else:
93-
lines = split_generic_value(element, indent)
92+
lines = split_generic_value(element, indent, line_length)
9493
elements.append(" " * indent + lines[0])
9594
elements.extend(lines[1:])
9695
return elements
@@ -151,15 +150,17 @@ def attempt_split_attribute(node, indent, line_length):
151150
lines = maybe_split_rval(rval, indent, offset, line_length)
152151
lines[0] = prefix + lines[0]
153152
return lines
154-
return [stringify_single_line(node)]
153+
return [" " * indent + stringify_single_line(node)]
155154

156155

157156
def stringify(node, indent, line_length):
158157
single_line = " " * indent + stringify_single_line(node)
159-
if len(single_line) < line_length:
158+
# Reserve 1 char for trailing ; or , after attributes
159+
effective_length = line_length - 1 if node.type == "attribute" else line_length
160+
if len(single_line) < effective_length:
160161
return [single_line]
161162
if node.type == "attribute":
162-
return attempt_split_attribute(node, indent, line_length)
163+
return attempt_split_attribute(node, indent, line_length - 1)
163164
return [single_line]
164165

165166

@@ -178,28 +179,106 @@ def autoformat(node, fmt, line_length, macro_indent, indent=0):
178179
if node.type in ["bundle_block", "promise_block", "body_block"]:
179180
line = " ".join(x.text.decode("utf-8") for x in node.children[0:-1])
180181
if not fmt.empty:
181-
fmt.print("", 0)
182+
prev_sib = node.prev_named_sibling
183+
if not (prev_sib and prev_sib.type == "comment"):
184+
fmt.print("", 0)
182185
fmt.print(line, 0)
183186
children = node.children[-1].children
184187
if node.type in [
185188
"bundle_section",
186189
"class_guarded_promises",
187190
"class_guarded_body_attributes",
191+
"class_guarded_promise_block_attributes",
188192
"promise",
193+
"half_promise",
189194
"attribute",
190195
]:
191196
indent += 2
192197
if node.type == "attribute":
193198
lines = stringify(node, indent, line_length)
194199
fmt.print_lines(lines, indent=0)
195200
return
201+
if node.type == "promise":
202+
# Single-line promise: if exactly 1 attribute, no half_promise continuation,
203+
# and the whole line fits in line_length
204+
attr_children = [c for c in children if c.type == "attribute"]
205+
next_sib = node.next_named_sibling
206+
has_continuation = next_sib and next_sib.type == "half_promise"
207+
if len(attr_children) == 1 and not has_continuation:
208+
promiser_node = next((c for c in children if c.type == "promiser"), None)
209+
if promiser_node:
210+
line = (
211+
text(promiser_node)
212+
+ " "
213+
+ stringify_single_line(attr_children[0])
214+
+ ";"
215+
)
216+
if indent + len(line) <= line_length:
217+
fmt.print(line, indent)
218+
return
196219
if children:
197220
for child in children:
221+
# Blank line between promises in a section
222+
if child.type == "promise":
223+
prev = child.prev_named_sibling
224+
if prev and prev.type in ["promise", "half_promise"]:
225+
fmt.print("", 0)
226+
elif child.type in [
227+
"class_guarded_promises",
228+
"class_guarded_body_attributes",
229+
"class_guarded_promise_block_attributes",
230+
]:
231+
prev = child.prev_named_sibling
232+
if prev and prev.type in [
233+
"promise",
234+
"half_promise",
235+
]:
236+
fmt.print("", 0)
237+
elif child.type == "comment":
238+
prev = child.prev_named_sibling
239+
if prev and prev.type in ["promise", "half_promise"]:
240+
parent = child.parent
241+
if parent and parent.type in [
242+
"bundle_section",
243+
"class_guarded_promises",
244+
]:
245+
fmt.print("", 0)
198246
autoformat(child, fmt, line_length, macro_indent, indent)
199247
return
200248
if node.type in [",", ";"]:
201249
fmt.print_same_line(node)
202250
return
251+
if node.type == "comment":
252+
comment_indent = indent
253+
next_sib = node.next_named_sibling
254+
while next_sib and next_sib.type == "comment":
255+
next_sib = next_sib.next_named_sibling
256+
if next_sib is None:
257+
prev_sib = node.prev_named_sibling
258+
while prev_sib and prev_sib.type == "comment":
259+
prev_sib = prev_sib.prev_named_sibling
260+
if prev_sib and prev_sib.type in [
261+
"bundle_section",
262+
"class_guarded_promises",
263+
"class_guarded_body_attributes",
264+
"class_guarded_promise_block_attributes",
265+
"promise",
266+
"half_promise",
267+
"attribute",
268+
]:
269+
comment_indent = indent + 2
270+
elif next_sib.type in [
271+
"bundle_section",
272+
"class_guarded_promises",
273+
"class_guarded_body_attributes",
274+
"class_guarded_promise_block_attributes",
275+
"promise",
276+
"half_promise",
277+
"attribute",
278+
]:
279+
comment_indent = indent + 2
280+
fmt.print(node, comment_indent)
281+
return
203282
fmt.print(node, indent)
204283

205284

tests/format/002_basics.expected.cf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# This shows some basics of policy language, without getting
22
# too deep into edge cases and wrappting etc.
3-
43
body common control
54
{
65
inputs => {"/var/cfengine/inputs/some_file.cf"};
@@ -24,6 +23,7 @@ bundle agent main
2423
"foo"
2524
if => "bar"
2625
string => "some_value";
26+
2727
baz::
2828
"bam"
2929
if => "bar"

tests/run-format-tests.sh

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#/usr/bin/env bash
22

3-
echo "TODO: Uncomment set -e to make tests start failing"
4-
5-
# set -e
3+
set -e
64
# set -x
75

86
echo "These tests expect cfengine CLI to be installed globally or in venv"

0 commit comments

Comments
 (0)