Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/config/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pub struct FormatterConfig {
/// Style that determines if a broken list, should keep its elements together on their own
/// line, before breaking individually.
pub prefer_compact: PreferCompact,
/// Keep single imports on a single line even if they exceed line length.
pub single_line_imports: bool,
}

/// Style of integer types.
Expand Down Expand Up @@ -251,6 +253,7 @@ impl Default for FormatterConfig {
pow_no_space: false,
prefer_compact: PreferCompact::default(),
docs_style: DocCommentStyle::default(),
single_line_imports: false,
}
}
}
1 change: 1 addition & 0 deletions crates/fmt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ The formatter supports multiple configuration options defined in `foundry.toml`.
| `contract_new_lines` | `false` | Add a new line at the start and end of contract declarations. |
| `sort_imports` | `false` | Sort import statements alphabetically in groups. A group is a set of imports separated by a newline. |
| `pow_no_space` | `false` | Suppress spaces around the power operator (`**`). |
| `single_line_imports` | `false` | Keep single imports on a single line, even if they exceed the line length limit. |

> Check [`FormatterConfig`](../config/src/fmt.rs) for a more detailed explanation.

Expand Down
28 changes: 20 additions & 8 deletions crates/fmt/src/state/sol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,22 +215,34 @@ impl<'ast> State<'_, 'ast> {
}

ast::ImportItems::Aliases(aliases) => {
self.s.cbox(self.ind);
// Check if we should keep single imports on one line
let use_single_line = self.config.single_line_imports && aliases.len() == 1;

if !use_single_line {
self.s.cbox(self.ind);
}
self.word("{");
self.braces_break();
if !use_single_line {
self.braces_break();
}

if self.config.sort_imports {
let aliases_iter: Box<dyn Iterator<Item = _>> = if self.config.sort_imports {
let mut sorted: Vec<_> = aliases.iter().collect();
sorted.sort_by_key(|(ident, _alias)| ident.name.as_str());
self.print_commasep_aliases(sorted.into_iter());
Box::new(sorted.into_iter())
} else {
self.print_commasep_aliases(aliases.iter());
Box::new(aliases.iter())
};
self.print_commasep_aliases(aliases_iter);

self.braces_break();
self.s.offset(-self.ind);
if !use_single_line {
self.braces_break();
self.s.offset(-self.ind);
}
self.word("}");
self.end();
if !use_single_line {
self.end();
}
self.word(" from ");
self.print_ast_str_lit(path);
}
Expand Down
30 changes: 30 additions & 0 deletions crates/fmt/testdata/SingleLineImports/fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Test cases for single_line_imports configuration

// Single import that exceeds line length (121 chars)
import {
ITransparentUpgradeableProxy
} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

// Single import with trailing comment
import {SomeContract} from "path/to/SomeContract.sol"; // This is a comment

// Single import with comment above
// This contract handles authentication
import {AuthManager} from "contracts/auth/AuthManager.sol";

// Multiple imports should still wrap regardless of config
import {
Contract1,
Contract2,
Contract3,
Contract4
} from "long/path/to/contracts.sol";

// Short single import
import {Token} from "Token.sol";

// Single import with alias
import {LongContractName as LCN} from "contracts/LongContractName.sol";

// Mixed comment styles
import {MixedComment} from "Mixed.sol"; /* block comment */ // line comment
23 changes: 23 additions & 0 deletions crates/fmt/testdata/SingleLineImports/original.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Test cases for single_line_imports configuration

// Single import that exceeds line length (121 chars)
import { ITransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

// Single import with trailing comment
import { SomeContract } from "path/to/SomeContract.sol"; // This is a comment

// Single import with comment above
// This contract handles authentication
import { AuthManager } from "contracts/auth/AuthManager.sol";

// Multiple imports should still wrap regardless of config
import { Contract1, Contract2, Contract3, Contract4 } from "long/path/to/contracts.sol";

// Short single import
import { Token } from "Token.sol";

// Single import with alias
import { LongContractName as LCN } from "contracts/LongContractName.sol";

// Mixed comment styles
import { MixedComment } from "Mixed.sol"; /* block comment */ // line comment
29 changes: 29 additions & 0 deletions crates/fmt/testdata/SingleLineImports/single-line.fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// config: single_line_imports = true
// Test cases for single_line_imports configuration

// Single import that exceeds line length (121 chars)
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

// Single import with trailing comment
import {SomeContract} from "path/to/SomeContract.sol"; // This is a comment

// Single import with comment above
// This contract handles authentication
import {AuthManager} from "contracts/auth/AuthManager.sol";

// Multiple imports should still wrap regardless of config
import {
Contract1,
Contract2,
Contract3,
Contract4
} from "long/path/to/contracts.sol";

// Short single import
import {Token} from "Token.sol";

// Single import with alias
import {LongContractName as LCN} from "contracts/LongContractName.sol";

// Mixed comment styles
import {MixedComment} from "Mixed.sol"; /* block comment */ // line comment
1 change: 1 addition & 0 deletions crates/fmt/tests/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ fmt_tests! {
RevertNamedArgsStatement,
RevertStatement,
SimpleComments,
SingleLineImports,
SortedImports,
StatementBlock,
StructDefinition,
Expand Down
4 changes: 3 additions & 1 deletion crates/forge/tests/cli/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ contract_new_lines = false
sort_imports = false
pow_no_space = false
prefer_compact = "all"
single_line_imports = false

[lint]
severity = []
Expand Down Expand Up @@ -1317,7 +1318,8 @@ forgetest_init!(test_default_config, |prj, cmd| {
"contract_new_lines": false,
"sort_imports": false,
"pow_no_space": false,
"prefer_compact": "all"
"prefer_compact": "all",
"single_line_imports": false
},
"lint": {
"severity": [],
Expand Down
Loading