Skip to content

Commit 123b3fa

Browse files
committed
feat: add stdin support with dash and stdin-filename option
- Replace --stdin flag with Unix-standard dash (-) for stdin input - Add --stdin-filename option for editor integration and context - Support both 'pint -' and 'pint --stdin-filename' patterns - Add comprehensive tests for stdin formatting scenarios
1 parent 02096d4 commit 123b3fa

File tree

3 files changed

+139
-41
lines changed

3 files changed

+139
-41
lines changed

app/Commands/DefaultCommand.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ protected function configure()
5151
new InputOption('cache-file', '', InputArgument::OPTIONAL, 'The path to the cache file'),
5252
new InputOption('parallel', 'p', InputOption::VALUE_NONE, 'Runs the linter in parallel (Experimental)'),
5353
new InputOption('max-processes', null, InputOption::VALUE_REQUIRED, 'The number of processes to spawn when using parallel execution'),
54-
new InputOption('stdin', null, InputOption::VALUE_NONE, 'Read and format code from standard input'),
54+
new InputOption('stdin-filename', null, InputOption::VALUE_REQUIRED, 'The path to use for stdin input (for config resolution and exclusions)'),
5555
],
5656
);
5757
}
@@ -76,12 +76,13 @@ public function handle($fixCode, $elaborateSummary)
7676

7777
/**
7878
* Fix the code sent to Pint on stdin and output to stdout.
79+
*
80+
* The stdin-filename option provides context for config resolution and
81+
* exclusion rules. Falls back to 'stdin.php' if not provided.
7982
*/
8083
protected function fixStdinInput(FixCode $fixCode): int
8184
{
82-
$paths = $this->argument('path');
83-
84-
$contextPath = ! empty($paths) ? $paths[0] : 'stdin.php';
85+
$contextPath = $this->option('stdin-filename') ?: 'stdin.php';
8586
$tempFile = sys_get_temp_dir().DIRECTORY_SEPARATOR.'pint_stdin_'.uniqid().'.php';
8687

8788
$this->input->setArgument('path', [$tempFile]);
@@ -106,9 +107,18 @@ protected function fixStdinInput(FixCode $fixCode): int
106107

107108
/**
108109
* Determine if there is input available on stdin.
110+
*
111+
* Stdin mode is triggered by either:
112+
* - Passing '-' as the path argument (Unix convention like Black, cat)
113+
* - Providing the --stdin-filename option (editor-friendly like Prettier)
109114
*/
110115
protected function hasStdinInput(): bool
111116
{
112-
return $this->option('stdin');
117+
$paths = $this->argument('path');
118+
119+
$hasStdinPlaceholder = ! empty($paths) && $paths[0] === '__STDIN_PLACEHOLDER__';
120+
$hasStdinFilename = ! empty($this->option('stdin-filename'));
121+
122+
return $hasStdinPlaceholder || $hasStdinFilename;
113123
}
114124
}

pint

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,27 @@ $app = require_once __DIR__.'/bootstrap/app.php';
4040

4141
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
4242

43+
/*
44+
|--------------------------------------------------------------------------
45+
| Handle Stdin Mode
46+
|--------------------------------------------------------------------------
47+
|
48+
| When using '-' to indicate stdin input (following Unix convention like
49+
| Black, cat, etc.), Symfony Console's ArgvInput parser fails because it
50+
| treats '-' as a malformed option. We work around this by replacing '-'
51+
| with a placeholder before the input is parsed. The DefaultCommand then
52+
| detects this placeholder to enable stdin mode.
53+
|
54+
*/
55+
56+
if (isset($_SERVER['argv'])) {
57+
$stdinIndex = array_search('-', $_SERVER['argv'], true);
58+
59+
if ($stdinIndex !== false) {
60+
$_SERVER['argv'][$stdinIndex] = '__STDIN_PLACEHOLDER__';
61+
}
62+
}
63+
4364
$status = $kernel->handle(
4465
$input = new Symfony\Component\Console\Input\ArgvInput,
4566
new Symfony\Component\Console\Output\ConsoleOutput

tests/Feature/StdinTest.php

Lines changed: 103 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,132 @@
33
use Illuminate\Support\Facades\Process;
44

55
it('formats code from stdin', function (string $input, ?string $expected) {
6-
$result = Process::input($input)->run('php pint app/Test.php --stdin')->throw();
6+
$result = Process::input($input)
7+
->run('php pint - --stdin-filename=app/Test.php')
8+
->throw();
79

810
expect($result)
9-
->output()->toBe($expected ?? $input)
10-
->errorOutput()->toBe('');
11+
->output()
12+
->toBe($expected ?? $input)
13+
->errorOutput()
14+
->toBe('');
1115
})->with([
1216
'basic array and conditional' => [
1317
<<<'PHP'
14-
<?php
15-
$array = array("a","b");
16-
if($condition==true){
17-
echo "test";
18-
}
19-
PHP,
18+
<?php
19+
$array = array("a","b");
20+
if($condition==true){
21+
echo "test";
22+
}
23+
PHP
24+
,
2025
<<<'PHP'
21-
<?php
26+
<?php
2227
23-
$array = ['a', 'b'];
24-
if ($condition == true) {
25-
echo 'test';
26-
}
28+
$array = ['a', 'b'];
29+
if ($condition == true) {
30+
echo 'test';
31+
}
2732

28-
PHP,
33+
PHP
34+
,
2935
],
3036
'class with method' => [
3137
<<<'PHP'
32-
<?php
33-
class Test{
34-
public function method(){
35-
return array("key"=>"value");
36-
}
37-
}
38-
PHP,
38+
<?php
39+
class Test{
40+
public function method(){
41+
return array("key"=>"value");
42+
}
43+
}
44+
PHP
45+
,
3946
<<<'PHP'
40-
<?php
47+
<?php
4148
42-
class Test
49+
class Test
50+
{
51+
public function method()
4352
{
44-
public function method()
45-
{
46-
return ['key' => 'value'];
47-
}
53+
return ['key' => 'value'];
4854
}
55+
}
4956

50-
PHP,
57+
PHP
58+
,
5159
],
5260
'already formatted code' => [
5361
<<<'PHP'
54-
<?php
62+
<?php
5563
56-
class AlreadyFormatted
64+
class AlreadyFormatted
65+
{
66+
public function method()
5767
{
58-
public function method()
59-
{
60-
return ['key' => 'value'];
61-
}
68+
return ['key' => 'value'];
6269
}
70+
}
6371

64-
PHP,
72+
PHP
73+
,
6574
null,
6675
],
6776
]);
77+
78+
it('formats code from stdin without filename', function () {
79+
$input = <<<'PHP'
80+
<?php
81+
$array = array("a","b");
82+
PHP;
83+
84+
$expected = <<<'PHP'
85+
<?php
86+
87+
$array = ['a', 'b'];
88+
89+
PHP;
90+
91+
$result = Process::input($input)->run('php pint -')->throw();
92+
93+
expect($result)->output()->toBe($expected)->errorOutput()->toBe('');
94+
});
95+
96+
it('uses stdin-filename for context', function () {
97+
$input = <<<'PHP'
98+
<?php
99+
$array = array("test");
100+
PHP;
101+
102+
$expected = <<<'PHP'
103+
<?php
104+
105+
$array = ['test'];
106+
107+
PHP;
108+
109+
$result = Process::input($input)
110+
->run('php pint - --stdin-filename=app/Models/User.php')
111+
->throw();
112+
113+
expect($result)->output()->toBe($expected)->errorOutput()->toBe('');
114+
});
115+
116+
it('formats code from stdin using only stdin-filename option', function () {
117+
$input = <<<'PHP'
118+
<?php
119+
$array = array("foo","bar");
120+
PHP;
121+
122+
$expected = <<<'PHP'
123+
<?php
124+
125+
$array = ['foo', 'bar'];
126+
127+
PHP;
128+
129+
$result = Process::input($input)
130+
->run('php pint --stdin-filename=app/Models/Example.php')
131+
->throw();
132+
133+
expect($result)->output()->toBe($expected)->errorOutput()->toBe('');
134+
});

0 commit comments

Comments
 (0)