summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Brunet <charles.brunet@optelgroup.com>2025-09-23 11:20:49 -0400
committerDylan Baker <dylan@pnwbakers.com>2025-09-24 08:13:04 -0700
commit97e9e2fb66895d2fc1b4a714a428468aeebf9648 (patch)
tree6189ef4480fe5703e5fabc6445e937f9031c141f
parentb91fede6d263286fa1e20d424f92d1e10668a8ed (diff)
downloadmeson-97e9e2fb66895d2fc1b4a714a428468aeebf9648.tar.gz
format: Fix indentation with parentheses
- Split long expressions in () according to max line length - Partly revert d028502 . Fixes #14935. - Fixes #15032.
-rw-r--r--mesonbuild/mformat.py79
-rw-r--r--mesonbuild/mparser.py3
-rw-r--r--test cases/format/1 default/indentation.meson10
-rw-r--r--test cases/format/5 transform/default.expected.meson15
-rw-r--r--test cases/format/5 transform/muon.expected.meson15
-rw-r--r--test cases/format/5 transform/options.expected.meson28
-rw-r--r--test cases/format/5 transform/source.meson27
7 files changed, 137 insertions, 40 deletions
diff --git a/mesonbuild/mformat.py b/mesonbuild/mformat.py
index 6b0429b2f..1bf7effd9 100644
--- a/mesonbuild/mformat.py
+++ b/mesonbuild/mformat.py
@@ -255,6 +255,19 @@ class MultilineArgumentDetector(FullAstVisitor):
super().visit_ArgumentNode(node)
+class MultilineParenthesesDetector(FullAstVisitor):
+
+ def __init__(self) -> None:
+ self.last_whitespaces: T.Optional[mparser.WhitespaceNode] = None
+
+ def enter_node(self, node: mparser.BaseNode) -> None:
+ self.last_whitespaces = None
+
+ def exit_node(self, node: mparser.BaseNode) -> None:
+ if node.whitespaces and node.whitespaces.value:
+ self.last_whitespaces = node.whitespaces
+
+
class TrimWhitespaces(FullAstVisitor):
def __init__(self, config: FormatterConfig):
@@ -288,6 +301,8 @@ class TrimWhitespaces(FullAstVisitor):
def add_space_after(self, node: mparser.BaseNode) -> None:
if not node.whitespaces.value:
node.whitespaces.value = ' '
+ elif '#' not in node.whitespaces.value:
+ node.whitespaces.value = ' '
def add_nl_after(self, node: mparser.BaseNode, force: bool = False) -> None:
if not node.whitespaces.value:
@@ -540,18 +555,28 @@ class TrimWhitespaces(FullAstVisitor):
def visit_ParenthesizedNode(self, node: mparser.ParenthesizedNode) -> None:
self.enter_node(node)
- is_multiline = node.lpar.lineno != node.rpar.lineno
- if is_multiline:
+ if node.lpar.whitespaces and '#' in node.lpar.whitespaces.value:
+ node.is_multiline = True
+
+ elif not node.is_multiline:
+ ml_detector = MultilineParenthesesDetector()
+ node.inner.accept(ml_detector)
+ if ml_detector.last_whitespaces and '\n' in ml_detector.last_whitespaces.value:
+ # We keep it multiline if last parenthesis is on a separate line
+ node.is_multiline = True
+
+ if node.is_multiline:
self.indent_comments += self.config.indent_by
node.lpar.accept(self)
node.inner.accept(self)
- if is_multiline:
+ if node.is_multiline:
node.inner.whitespaces.value = self.dedent(node.inner.whitespaces.value)
self.indent_comments = self.dedent(self.indent_comments)
- if node.lpar.whitespaces and '\n' in node.lpar.whitespaces.value:
- self.add_nl_after(node.inner)
+ self.add_nl_after(node.inner)
+ else:
+ node.inner.whitespaces = None
node.rpar.accept(self)
self.move_whitespaces(node.rpar, node)
@@ -564,6 +589,7 @@ class ArgumentFormatter(FullAstVisitor):
self.level = 0
self.indent_after = False
self.is_function_arguments = False
+ self.par_level = 0
def add_space_after(self, node: mparser.BaseNode) -> None:
if not node.whitespaces.value:
@@ -573,7 +599,7 @@ class ArgumentFormatter(FullAstVisitor):
if not node.whitespaces.value or node.whitespaces.value == ' ':
node.whitespaces.value = '\n'
indent_by = (node.condition_level + indent) * self.config.indent_by
- if indent_by:
+ if indent_by and node.whitespaces.value.endswith('\n'):
node.whitespaces.value += indent_by
def visit_ArrayNode(self, node: mparser.ArrayNode) -> None:
@@ -682,11 +708,11 @@ class ArgumentFormatter(FullAstVisitor):
# keep '--arg', 'value' on same line
self.add_space_after(node.commas[arg_index])
elif arg_index < len(node.commas):
- self.add_nl_after(node.commas[arg_index], self.level)
+ self.add_nl_after(node.commas[arg_index], self.level + self.par_level)
arg_index += 1
for comma in node.commas[arg_index:-1]:
- self.add_nl_after(comma, self.level)
+ self.add_nl_after(comma, self.level + self.par_level)
if node.arguments or node.kwargs:
self.add_nl_after(node, self.level - 1)
@@ -701,17 +727,38 @@ class ArgumentFormatter(FullAstVisitor):
def visit_ParenthesizedNode(self, node: mparser.ParenthesizedNode) -> None:
self.enter_node(node)
- is_multiline = '\n' in node.lpar.whitespaces.value
- if is_multiline:
+ if node.is_multiline:
+ self.par_level += 1
current_indent_after = self.indent_after
self.indent_after = True
node.lpar.accept(self)
+ if node.is_multiline:
+ self.add_nl_after(node.lpar, indent=self.level + self.par_level)
node.inner.accept(self)
- if is_multiline:
+ if node.is_multiline:
+ self.par_level -= 1
self.indent_after = current_indent_after
node.rpar.accept(self)
self.exit_node(node)
+ def visit_OrNode(self, node: mparser.OrNode) -> None:
+ self.enter_node(node)
+ node.left.accept(self)
+ if self.par_level:
+ self.add_nl_after(node.left, indent=self.level + self.par_level)
+ node.operator.accept(self)
+ node.right.accept(self)
+ self.exit_node(node)
+
+ def visit_AndNode(self, node: mparser.AndNode) -> None:
+ self.enter_node(node)
+ node.left.accept(self)
+ if self.par_level:
+ self.add_nl_after(node.left, indent=self.level + self.par_level)
+ node.operator.accept(self)
+ node.right.accept(self)
+ self.exit_node(node)
+
class ComputeLineLengths(FullAstVisitor):
@@ -811,6 +858,16 @@ class ComputeLineLengths(FullAstVisitor):
self.split_if_needed(node.args) # split if closing bracket is too far
self.exit_node(node)
+ def visit_ParenthesizedNode(self, node: mparser.ParenthesizedNode) -> None:
+ self.enter_node(node)
+ node.lpar.accept(self)
+ node.inner.accept(self)
+ node.rpar.accept(self)
+ if not node.is_multiline and self.length > self.config.max_line_length:
+ node.is_multiline = True
+ self.need_regenerate = True
+ self.exit_node(node)
+
class SubdirFetcher(FullAstVisitor):
diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py
index 3dd8f0a5e..a42fcdb06 100644
--- a/mesonbuild/mparser.py
+++ b/mesonbuild/mparser.py
@@ -656,13 +656,14 @@ class ParenthesizedNode(BaseNode):
lpar: SymbolNode = field(hash=False)
inner: BaseNode
rpar: SymbolNode = field(hash=False)
+ is_multiline: bool
def __init__(self, lpar: SymbolNode, inner: BaseNode, rpar: SymbolNode):
super().__init__(lpar.lineno, lpar.colno, inner.filename, end_lineno=rpar.lineno, end_colno=rpar.colno+1)
self.lpar = lpar
self.inner = inner
self.rpar = rpar
-
+ self.is_multiline = False
if T.TYPE_CHECKING:
COMPARISONS = Literal['==', '!=', '<', '<=', '>=', '>', 'in', 'notin']
diff --git a/test cases/format/1 default/indentation.meson b/test cases/format/1 default/indentation.meson
index f18b23072..7b26e49b1 100644
--- a/test cases/format/1 default/indentation.meson
+++ b/test cases/format/1 default/indentation.meson
@@ -100,3 +100,13 @@ n = [
2,
3,
]
+
+# Overindent regressions (issue #14935)
+if (host_cpu_family == 'x86' and host_system in [
+ 'cygwin',
+ 'windows',
+ 'os2',
+ 'interix',
+])
+ message('hi')
+endif
diff --git a/test cases/format/5 transform/default.expected.meson b/test cases/format/5 transform/default.expected.meson
index 4a9851ac9..702ae5643 100644
--- a/test cases/format/5 transform/default.expected.meson
+++ b/test cases/format/5 transform/default.expected.meson
@@ -8,7 +8,7 @@ f = files(options_ini, 'expected.meson', 'source.meson')
# This array should fit on one line
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
-# This array is too long and should be splitted
+# This array is too long and should be split
a2 = [
2,
3,
@@ -81,4 +81,17 @@ arguments = [
'--x',
]
+# issue #15032
+if true
+ if true
+ if (
+ true
+ and true
+ and false
+ )
+ message('Hello, world!')
+ endif
+ endif
+endif
+
# no final endline
diff --git a/test cases/format/5 transform/muon.expected.meson b/test cases/format/5 transform/muon.expected.meson
index 3b6127030..f01849734 100644
--- a/test cases/format/5 transform/muon.expected.meson
+++ b/test cases/format/5 transform/muon.expected.meson
@@ -8,7 +8,7 @@ f = files('expected.meson', 'source.meson', options_ini)
# This array should fit on one line
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
-# This array is too long and should be splitted
+# This array is too long and should be split
a2 = [
2,
3,
@@ -81,4 +81,17 @@ arguments = [
'--x',
]
+# issue #15032
+if true
+ if true
+ if (
+ true
+ and true
+ and false
+ )
+ message('Hello, world!')
+ endif
+ endif
+endif
+
# no final endline
diff --git a/test cases/format/5 transform/options.expected.meson b/test cases/format/5 transform/options.expected.meson
index 84917c19d..7136506c0 100644
--- a/test cases/format/5 transform/options.expected.meson
+++ b/test cases/format/5 transform/options.expected.meson
@@ -8,25 +8,14 @@ f = files(options_ini, 'expected.meson', 'source.meson')
# This array should fit on one line
a1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 ]
-# This array is too long and should be splitted
+# This array is too long and should be split
a2 = [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ]
# space array
a3 = [ 1, 2, 3 ]
# multi line expression
-is_foo = (
- true
- and false
- and true
- and false
- and true
- and false
- and true
- and false
- and true
- and false
-)
+is_foo = (true and false and true and false and true and false and true and false and true and false)
# no single comma function
fct = files(
@@ -60,4 +49,17 @@ arguments = [
'--x',
]
+# issue #15032
+if true
+ if true
+ if (
+ true
+ and true
+ and false
+ )
+ message('Hello, world!')
+ endif
+ endif
+endif
+
# no final endline \ No newline at end of file
diff --git a/test cases/format/5 transform/source.meson b/test cases/format/5 transform/source.meson
index a3b326b12..554b9e6a7 100644
--- a/test cases/format/5 transform/source.meson
+++ b/test cases/format/5 transform/source.meson
@@ -12,25 +12,14 @@ f = files(
# This array should fit on one line
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
-# This array is too long and should be splitted
+# This array is too long and should be split
a2 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
# space array
a3 = [ 1, 2, 3 ]
# multi line expression
-is_foo = (
- true
- and false
- and true
- and false
- and true
- and false
- and true
- and false
- and true
- and false
-)
+is_foo = (true and false and true and false and true and false and true and false and true and false)
# no single comma function
fct = files(
@@ -49,4 +38,16 @@ f'This is not a fstring'
arguments = ['a', '--opt_a', 'opt_a_value', 'b', 'c', '--opt_d', '--opt_e', 'opt_e_value',
'--opt_f', '--opt_g', 'opt_g_value', 'other_value', 'again', '--x']
+# issue #15032
+if true
+ if true
+ if (true and
+ true and
+ false
+ )
+ message('Hello, world!')
+ endif
+ endif
+endif
+
# no final endline \ No newline at end of file