Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ecma function call arguments indents are incorrect #6036

Open
LeviOP opened this issue Feb 1, 2024 · 1 comment
Open

ecma function call arguments indents are incorrect #6036

LeviOP opened this issue Feb 1, 2024 · 1 comment
Labels
indent Issues or PRs about indentation queries or module

Comments

@LeviOP
Copy link
Contributor

LeviOP commented Feb 1, 2024

While programming in javascript/typescript, I have noticed many problems with function call argument indentation. I finally decided to look into why I'm having problems, and discovered three different, but related problems with ecma indents that all result in over-indentation.

I've decided not to make any pull requests as javascript and typescript are some of the most used languages today, and changing the way that they are indented could potentially effect thousands of people.

First, the bug that made me look into this. The following is code indented by nvim-treesitter:

console.log({
    key: "value"
}, {
        key: "value"
    });

The reason the code is indented like this is because the children of arguments nodes are indented, but also the children of array, object and parenthesized_expression nodes:

[
(arguments)
(array)
(binary_expression)
(class_body)
(export_clause)
(formal_parameters)
(named_imports)
(object)
(object_pattern)
(parenthesized_expression)
(return_statement)
(statement_block)
(switch_case)
(switch_default)
(switch_statement)
(template_substitution)
(ternary_expression)
] @indent.begin

The first object is not indented because part of the object node (the opening {) starts on the same line as the arguments node. Subsequent nodes, though, are indented once because they are a child of the arguments node, and then again their contents are indented as they should be.

We can see the reasoning for these all being indented if we format the code in the way that it expects:

console.log(
    {
        key: "value"
    }, {
        key: "value"
    }
);

The problem is that tree-sitter doesn't know that the only reason the children of the arguments node are on a new line is because the nodes themselves are multi-line. How to solve this (or if it even is possible to solve), I'm not sure. But while exploring the ecma indents, I discovered another related issue which causes multiple indents. The following is code indented by nvim-treesitter:

console.log
(
        {
            key: "value"
        }, {
            key: "value"
        }
    );

There are two reasons the code appears this way. First, all arguments nodes which have an object node as a child will branch their indentation:

[
(arguments
(object))
")"
"}"
"]"
] @indent.branch

I cannot think of any reason why this would be the case. This statement was included in the original commit of the ecma indents file, and seems to have been kept around because no one knows what it does. Removing it makes the code indent like this:

console.log
    (
        {
            key: "value"
        }, {
            key: "value"
        }
    );

This looks better, but still has a problem in my eyes: The arguments node (the parentheses and everything inside) is indented when not on the same line as the function identifier (as can be seen above). This doesn't look bad, but isn't in line with how indenting traditionally works. Usually, an indent occurs when a block (or other multi-line expression) starts, but does not end on the same line. In the above code, there is no block that starts in the first line that isn't continued that would create need for an indent. (Note: Not necessarily an authority, but code formatters like eslint/stylistic and prettier suggest that there should be no indentation for arguments on a new line, as I have suggested.)

This could easily be solved by removing these queries: (added in this commit)

(arguments
(call_expression) @indent.begin)
(binary_expression
(call_expression) @indent.begin)
(expression_statement
(call_expression) @indent.begin)

Removing them makes indentation look like this:

console.log
(
    {
        key: "value"
    }, {
        key: "value"
    }
);

In my mind, this is correct.

In summary, there are three issues:

  1. tree-sitter indents all children of the arguments node, even though we don't intend for them to be "multi-line" arguments (in the sense that each argument goes on its own line). I have no idea how this could be solved
  2. arguments nodes that include an object are branched for seemingly no reason. This can easily be solved.
  3. arguments nodes that are on a separate line than their function identifier are indented. This could be easily fixed, but it could be argued that this is a matter of personal preference, and it appears that this functionality was added on purpose.

I would appreciate opinions/insight on the things I have brought up. Thanks.

@lucario387
Copy link
Member

:) is the only word I can drop

I will try to come up with something better later. Probably needing a line-based predicate for that

@clason clason added the indent Issues or PRs about indentation queries or module label Feb 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
indent Issues or PRs about indentation queries or module
Projects
None yet
Development

No branches or pull requests

3 participants