diff options
| author | Charles Brunet <charles.brunet@optelgroup.com> | 2025-09-23 11:20:49 -0400 |
|---|---|---|
| committer | Dylan Baker <dylan@pnwbakers.com> | 2025-09-24 08:13:04 -0700 |
| commit | 97e9e2fb66895d2fc1b4a714a428468aeebf9648 (patch) | |
| tree | 6189ef4480fe5703e5fabc6445e937f9031c141f | |
| parent | b91fede6d263286fa1e20d424f92d1e10668a8ed (diff) | |
| download | meson-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.py | 79 | ||||
| -rw-r--r-- | mesonbuild/mparser.py | 3 | ||||
| -rw-r--r-- | test cases/format/1 default/indentation.meson | 10 | ||||
| -rw-r--r-- | test cases/format/5 transform/default.expected.meson | 15 | ||||
| -rw-r--r-- | test cases/format/5 transform/muon.expected.meson | 15 | ||||
| -rw-r--r-- | test cases/format/5 transform/options.expected.meson | 28 | ||||
| -rw-r--r-- | test cases/format/5 transform/source.meson | 27 |
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 |
