Skip to content

Commit

Permalink
Merge branch 'refactor-hanging-indentation'
Browse files Browse the repository at this point in the history
  • Loading branch information
lkrms committed Jan 3, 2025
2 parents 73da344 + d5770e4 commit eac9778
Show file tree
Hide file tree
Showing 59 changed files with 2,373 additions and 998 deletions.
30 changes: 14 additions & 16 deletions docs/Indentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,34 +255,32 @@ After finding a token to indent, `HangingIndentation` creates a context for it,
and if indentation for that context has already been applied, the token is not
indented further.

A token's context is comprised of its parent token (or `null` if it's a
top-level token), and an optional anchor token shared by any siblings that
should receive the same level of indentation.
A token's context is an `array{?Token, ?Token, ?Token, 3?:Token|int, 4?:int}`
comprised of:

- its parent (or `null` if it's a top-level token)
- the most recent assignment operator or `T_DOUBLE_ARROW` in the same statement
(or `null` if it isn't part of an expression after an assignment or `=>`)
- its ternary context (or `null` if it isn't part of a ternary expression)
- an optional token and/or precedence value shared by any siblings that should
receive the same level of indentation

The aim is to differentiate between lines where a new expression starts, and
lines where an expression continues:

```php
$iterator = new RecursiveDirectoryIterator($dir,
FilesystemIterator::KEY_AS_PATHNAME |
FilesystemIterator::CURRENT_AS_FILEINFO |
FilesystemIterator::SKIP_DOTS);
```

```php
return is_string($contents)
? $contents
: json_encode($contents, JSON_PRETTY_PRINT);
```

```php
<?php
fn($a, $b) =>
$a === $b
? 0
: $a <=>
$b;
```

There are many more examples in the `HangingIndentation` [unit
test][HangingIndentationTest].

[mixed]: #mixed-indentation
[PSR-12]: https://www.php-fig.org/psr/psr-12/
[PER]: https://www.php-fig.org/per/coding-style/
[HangingIndentationTest]: ../tests/unit/Rule/HangingIndentationTest.php
24 changes: 17 additions & 7 deletions docs/Rules.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/App/PrettyPHPCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ protected function run(...$params)
$dir = dirname($inputFile);
$formatter = $this->FormatterByDir[$dir] ??=
$this->DefaultFormatter ??=
$this->getFormatter();
$this->getFormatter();

$inputStream = File::open($file, 'rb');

Expand Down
40 changes: 20 additions & 20 deletions src/Catalog/TokenData.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,90 +15,90 @@ interface TokenData
*/
public const COMMENT_CONTENT = 0;

/**
* The token ID of the delimiter associated with a LIST_PARENT token
*/
public const LIST_DELIMITER = 1;

/**
* A collection of items associated with a LIST_PARENT token
*/
public const LIST_ITEMS = 1;
public const LIST_ITEMS = 2;

/**
* The number of items associated with a LIST_PARENT token
*/
public const LIST_ITEM_COUNT = 2;
public const LIST_ITEM_COUNT = 3;

/**
* The LIST_PARENT of the first token in a LIST_ITEM
*/
public const LIST_PARENT = 3;
public const LIST_PARENT = 4;

/**
* The T_COLON or T_QUESTION associated with a T_QUESTION or T_COLON flagged
* as a TERNARY_OPERATOR
*/
public const OTHER_TERNARY_OPERATOR = 4;
public const OTHER_TERNARY_OPERATOR = 5;

/**
* The last token of the string opened by the token
*/
public const STRING_CLOSED_BY = 5;
public const STRING_CLOSED_BY = 6;

/**
* The first T_OBJECT_OPERATOR or T_NULLSAFE_OBJECT_OPERATOR in a chain
* thereof
*/
public const CHAIN_OPENED_BY = 6;
public const CHAIN_OPENED_BY = 7;

/**
* A collection of tokens that form a NAMED_DECLARATION
*/
public const NAMED_DECLARATION_PARTS = 7;
public const NAMED_DECLARATION_PARTS = 8;

/**
* The type of a NAMED_DECLARATION
*/
public const NAMED_DECLARATION_TYPE = 8;
public const NAMED_DECLARATION_TYPE = 9;

/**
* A collection of property hooks for a NAMED_DECLARATION with type PROPERTY
* or PROMOTED_PARAM
*/
public const PROPERTY_HOOKS = 9;
public const PROPERTY_HOOKS = 10;

/**
* A list of closures that align other tokens with the token when its output
* column changes
*/
public const ALIGNMENT_CALLBACKS = 10;
public const ALIGNMENT_CALLBACKS = 11;

/**
* The control structure a T_OPEN_UNENCLOSED token is associated with
*/
public const UNENCLOSED_PARENT = 11;
public const UNENCLOSED_PARENT = 12;

/**
* Whether or not the control structure a T_OPEN_UNENCLOSED token is
* associated with continues after its T_CLOSE_UNENCLOSED counterpart
*/
public const UNENCLOSED_CONTINUES = 12;
public const UNENCLOSED_CONTINUES = 13;

/**
* The non-virtual token a virtual token is bound to
*/
public const BOUND_TO = 13;
public const BOUND_TO = 14;

/**
* The last non-virtual token before a virtual token, or null if there is no
* such token
*/
public const PREV_REAL = 14;
public const PREV_REAL = 15;

/**
* The next non-virtual token after a virtual token, or null if there is no
* such token
*/
public const NEXT_REAL = 15;

/**
* The type applied to an open bracket by the HangingIndentation rule
*/
public const HANGING_INDENT_PARENT_TYPE = 16;
public const NEXT_REAL = 16;
}
126 changes: 63 additions & 63 deletions src/Contract/HasOperatorPrecedence.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,69 +17,69 @@ interface HasOperatorPrecedence
* @var array<int,array<array{int,int,bool,bool}>>
*/
public const OPERATOR_PRECEDENCE = [
\T_CLONE => [[0, 0, false, false]],
\T_NEW => [[0, 0, false, false]],
\T_POW => [[0, 1, false, true]],
\T_PLUS => [[self::UNARY, 2, false, false], [self::BINARY, 6, true, false]],
\T_MINUS => [[self::UNARY, 2, false, false], [self::BINARY, 6, true, false]],
\T_INC => [[0, 2, false, false]],
\T_DEC => [[0, 2, false, false]],
\T_NOT => [[0, 2, false, false]],
\T_INT_CAST => [[0, 2, false, false]],
\T_DOUBLE_CAST => [[0, 2, false, false]],
\T_STRING_CAST => [[0, 2, false, false]],
\T_ARRAY_CAST => [[0, 2, false, false]],
\T_OBJECT_CAST => [[0, 2, false, false]],
\T_BOOL_CAST => [[0, 2, false, false]],
\T_UNSET_CAST => [[0, 2, false, false]],
\T_AT => [[0, 2, false, false]],
\T_INSTANCEOF => [[0, 3, true, false]],
\T_LOGICAL_NOT => [[0, 4, false, false]],
\T_MUL => [[0, 5, true, false]],
\T_DIV => [[0, 5, true, false]],
\T_MOD => [[0, 5, true, false]],
\T_SL => [[0, 7, true, false]],
\T_SR => [[0, 7, true, false]],
\T_CONCAT => [[0, 8, true, false]],
\T_SMALLER => [[0, 9, false, false]],
\T_IS_SMALLER_OR_EQUAL => [[0, 9, false, false]],
\T_GREATER => [[0, 9, false, false]],
\T_IS_GREATER_OR_EQUAL => [[0, 9, false, false]],
\T_IS_EQUAL => [[0, 10, false, false]],
\T_IS_NOT_EQUAL => [[0, 10, false, false]],
\T_IS_IDENTICAL => [[0, 10, false, false]],
\T_IS_NOT_IDENTICAL => [[0, 10, false, false]],
\T_SPACESHIP => [[0, 10, false, false]],
\T_AND => [[0, 11, true, false]],
\T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG => [[0, 11, true, false]],
\T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => [[0, 11, true, false]],
\T_XOR => [[0, 12, true, false]],
\T_OR => [[0, 13, true, false]],
\T_BOOLEAN_AND => [[0, 14, true, false]],
\T_BOOLEAN_OR => [[0, 15, true, false]],
\T_COALESCE => [[0, 16, false, true]],
\T_QUESTION => [[self::TERNARY, 17, false, false]],
\T_COLON => [[self::TERNARY, 17, false, false]],
\T_EQUAL => [[0, 18, false, true]],
\T_PLUS_EQUAL => [[0, 18, false, true]],
\T_MINUS_EQUAL => [[0, 18, false, true]],
\T_MUL_EQUAL => [[0, 18, false, true]],
\T_POW_EQUAL => [[0, 18, false, true]],
\T_DIV_EQUAL => [[0, 18, false, true]],
\T_CONCAT_EQUAL => [[0, 18, false, true]],
\T_MOD_EQUAL => [[0, 18, false, true]],
\T_AND_EQUAL => [[0, 18, false, true]],
\T_OR_EQUAL => [[0, 18, false, true]],
\T_XOR_EQUAL => [[0, 18, false, true]],
\T_SL_EQUAL => [[0, 18, false, true]],
\T_SR_EQUAL => [[0, 18, false, true]],
\T_COALESCE_EQUAL => [[0, 18, false, true]],
\T_YIELD_FROM => [[0, 19, false, false]],
\T_YIELD => [[0, 20, false, false]],
\T_PRINT => [[0, 21, false, false]],
\T_LOGICAL_AND => [[0, 22, true, false]],
\T_LOGICAL_XOR => [[0, 23, true, false]],
\T_LOGICAL_OR => [[0, 24, true, false]],
\T_CLONE => [[0, 1, false, false]],
\T_NEW => [[0, 1, false, false]],
\T_POW => [[0, 2, false, true]],
\T_PLUS => [[self::UNARY, 3, false, false], [self::BINARY, 7, true, false]],
\T_MINUS => [[self::UNARY, 3, false, false], [self::BINARY, 7, true, false]],
\T_INC => [[0, 3, false, false]],
\T_DEC => [[0, 3, false, false]],
\T_NOT => [[0, 3, false, false]],
\T_INT_CAST => [[0, 3, false, false]],
\T_DOUBLE_CAST => [[0, 3, false, false]],
\T_STRING_CAST => [[0, 3, false, false]],
\T_ARRAY_CAST => [[0, 3, false, false]],
\T_OBJECT_CAST => [[0, 3, false, false]],
\T_BOOL_CAST => [[0, 3, false, false]],
\T_UNSET_CAST => [[0, 3, false, false]],
\T_AT => [[0, 3, false, false]],
\T_INSTANCEOF => [[0, 4, true, false]],
\T_LOGICAL_NOT => [[0, 5, false, false]],
\T_MUL => [[0, 6, true, false]],
\T_DIV => [[0, 6, true, false]],
\T_MOD => [[0, 6, true, false]],
\T_SL => [[0, 8, true, false]],
\T_SR => [[0, 8, true, false]],
\T_CONCAT => [[0, 9, true, false]],
\T_SMALLER => [[0, 10, false, false]],
\T_IS_SMALLER_OR_EQUAL => [[0, 10, false, false]],
\T_GREATER => [[0, 10, false, false]],
\T_IS_GREATER_OR_EQUAL => [[0, 10, false, false]],
\T_IS_EQUAL => [[0, 11, false, false]],
\T_IS_NOT_EQUAL => [[0, 11, false, false]],
\T_IS_IDENTICAL => [[0, 11, false, false]],
\T_IS_NOT_IDENTICAL => [[0, 11, false, false]],
\T_SPACESHIP => [[0, 11, false, false]],
\T_AND => [[0, 12, true, false]],
\T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG => [[0, 12, true, false]],
\T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG => [[0, 12, true, false]],
\T_XOR => [[0, 13, true, false]],
\T_OR => [[0, 14, true, false]],
\T_BOOLEAN_AND => [[0, 15, true, false]],
\T_BOOLEAN_OR => [[0, 16, true, false]],
\T_COALESCE => [[0, 17, false, true]],
\T_QUESTION => [[self::TERNARY, 18, false, false]],
\T_COLON => [[self::TERNARY, 18, false, false]],
\T_EQUAL => [[0, 19, false, true]],
\T_PLUS_EQUAL => [[0, 19, false, true]],
\T_MINUS_EQUAL => [[0, 19, false, true]],
\T_MUL_EQUAL => [[0, 19, false, true]],
\T_POW_EQUAL => [[0, 19, false, true]],
\T_DIV_EQUAL => [[0, 19, false, true]],
\T_CONCAT_EQUAL => [[0, 19, false, true]],
\T_MOD_EQUAL => [[0, 19, false, true]],
\T_AND_EQUAL => [[0, 19, false, true]],
\T_OR_EQUAL => [[0, 19, false, true]],
\T_XOR_EQUAL => [[0, 19, false, true]],
\T_SL_EQUAL => [[0, 19, false, true]],
\T_SR_EQUAL => [[0, 19, false, true]],
\T_COALESCE_EQUAL => [[0, 19, false, true]],
\T_YIELD_FROM => [[0, 20, false, false]],
\T_YIELD => [[0, 21, false, false]],
\T_PRINT => [[0, 22, false, false]],
\T_LOGICAL_AND => [[0, 23, true, false]],
\T_LOGICAL_XOR => [[0, 24, true, false]],
\T_LOGICAL_OR => [[0, 25, true, false]],
\T_DOUBLE_ARROW => [[0, 99, false, false]],
\T_BREAK => [[0, 99, false, false]],
\T_CASE => [[0, 99, false, false]],
Expand Down
12 changes: 6 additions & 6 deletions src/Contract/ListRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ interface ListRule extends Rule
/**
* Apply the rule to a token and the list of items associated with it
*
* If `$parent` is a `T_OPEN_PARENTHESIS`, `T_OPEN_BRACKET` or `T_ATTRIBUTE`
* token, `$items` has at least one item.
* If `$parent` is a `T_OPEN_PARENTHESIS`, `T_OPEN_BRACKET`, `T_OPEN_BRACE`
* or `T_ATTRIBUTE` token, `$items` has at least one item.
*
* Otherwise, `$parent` is a `T_EXTENDS` or `T_IMPLEMENTS` token, and
* Otherwise, `$parent` is a `T_EXTENDS`, `T_IMPLEMENTS`, `T_CONST`,
* `T_USE`, `T_INSTEADOF`, `T_STATIC`, `T_GLOBAL` or modifier token, and
* `$items` has at least two items.
*
* Each token in `$items` is the first code token after `$parent` or a
* delimiter.
*
* This method is not called for empty lists or for classes that extend or
* implement fewer than two interfaces.
* This method is not called for empty lists.
*/
public function processList(Token $parent, TokenCollection $items): void;
public function processList(Token $parent, TokenCollection $items, Token $lastChild): void;
}
Loading

0 comments on commit eac9778

Please sign in to comment.