zed
zed copied to clipboard
External formatter for PHP replaces the original file
Check for existing issues
- [X] Completed
Describe the bug / provide steps to reproduce it
I am trying to configure PHP CS Fixer as an external formatter for PHP using the following settings:
{
"language_overrides": {
"PHP": {
"formatter": {
"external": {
"command": "php-cs-fixer",
"arguments": [
"fix",
"--using-cache=no",
"{buffer_path}"
]
}
}
}
}
}
On save, the formatter seems to be working just fine and it fixes the issues, but the content of the original file gets overwritten by the verbose output of the formatter command:
Environment
Zed: v0.103.1 (stable) OS: macOS 13.5.0 Memory: 8 GiB Architecture: aarch64
If applicable, add mockups / screenshots to help explain present your vision of the feature
No response
If applicable, attach your ~/Library/Logs/Zed/Zed.log
file to this issue.
If you only need the most recent lines, you can run the zed: open log
command palette action to see the last 1000.
2023-09-14T06:53:59 [ERROR] unexpected item event after pane was dropped
@maxbrunsfeld, I realize these are different languagees and tools, but this feels similar to:
- https://github.com/zed-industries/zed/issues/4514
Seems a PR for it in the main repo of php-cs-fixer https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/pull/4320 Can't wait for that, so I made a custom script to make it work for php-cs-fixer https://gist.github.com/vuon9/be16429f751e12f72e220c18777d9bc7
And configuration will be like this
{
"language_overrides": {
"PHP": {
"formatter": {
"external": {
"command": "php-cs-fixer-std",
"arguments": [
"fix",
"--config=www/.php-cs-fixer.php",
"--using-cache=no",
"{buffer_path}"
]
}
},
"format_on_save": "on"
}
}
}
I was just battling with this, thanks for the script @vuon9! One thing that I found is that I use Herd to manage my PHP versions so the shebang didn't work for me. I had to update it to #!/usr/bin/env php
and then your script worked great!
Looking forward to native support for formatters updating the file and not relying on the output 😊
Even though we could technically make it work from the standpoint of the linter, I still favor the option of Zed disregarding the stdout output of the linter, but pls keep the new change of file after lint tool completes its process on the file. Linter tools can output anything they want through stdout, even if it's improper way.
Laravel's Pint has the same issue so I created a script to fake a formatter mode for it: https://gist.github.com/gabrielbidula/4b8f84a02dafd242b0e1cf1d682fcaac Then the settings should look like this:
"PHP": {
"format_on_save": "on",
"formatter": {
"external": {
"command": "/path/to/pint.sh",
"arguments": [
"{buffer_path}"
]
}
}
},
Laravel's Pint has the same issue so I created a script to fake a formatter mode for it: https://gist.github.com/gabrielbidula/4b8f84a02dafd242b0e1cf1d682fcaac Then the settings should look like this:
"PHP": { "format_on_save": "on", "formatter": { "external": { "command": "/path/to/pint.sh", "arguments": [ "{buffer_path}" ] } } },
If I type something, then delete it, and save/format again, it comes back. Any idea why this could be happening?
https://github.com/zed-industries/zed/assets/67285754/36e6f49c-ee9c-4b9b-a77b-bc5bbace74ae
@malssid I'm experiencing the same issues all of a sudden - I've tried adding sleep 1
before cat
, but I think it's some weird buffering going on in Zed.
I've been able to make this work with:
.zed/settings.json
{
"language_overrides": {
"PHP": {
"formatter": {
"external": {
"command": "./pint.sh",
"arguments": ["{buffer_text}"]
}
}
}
}
}
And then a simple script inside ./pint.sh
file, in project root like:
#!/bin/bash
# Create a temporary file
temp_file="_temp_pint.php"
# Read STDIN buffer and save it to the temporary file
cat > "$temp_file"
# Run the pint command
./vendor/bin/pint --quiet "$temp_file"
# Read the modified file and return its contents
cat "$temp_file"
And then have a temporary _temp_pint.php
file (can be added empty to the repo, but excluded from changes in git) that is used for the formatting on save and returns the buffer.
cc @FrittenKeeZ , @malssid
@latorante I changed my logic to use serbanrobu's snippet (slightly modified) from a Pint issue - https://github.com/laravel/pint/issues/162#issuecomment-1645114713
.zed/settings.json
:
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings
{
"languages": {
"PHP": {
"preferred_line_length": 120,
"soft_wrap": "preferred_line_length",
"formatter": {
"external": {
"command": ".zed/pint.sh",
"arguments": ["{buffer_text}"]
}
}
}
}
}
.zed/pint.sh
:
#!/bin/bash
file="$(mktemp --tmpdir=/tmp)"
cat - >"$file"
./vendor/bin/pint -q "$file"
cat "$file"
rm "$file"
Using PHP-CS-Fixer, this one-line has been working fine for me for a few days now.
Using the scripts shared previously in this thread, my changes where often not persisting due to an issue with how Zed handles the file at {buffer_path}
.
Adjust the paths and the arguments for you needs :
{
"languages": {
"PHP": {
"format_on_save": "on",
"formatter": {
"external": {
"command": "bash",
"arguments": [
"-c",
"cat > /tmp/zed_php_cs_fixer && php-cs-fixer fix --using-cache=no --quiet /tmp/zed_php_cs_fixer && cat /tmp/zed_php_cs_fixer"
]
}
}
}
}
}
Explanation of the issue :
PHP-CS-Fixer can only work on a file and doesn't support STDIN/STDOUT.
Zed overwrites the file at {buffer_path}
with stale data, so we have to use STDIN/STDOUT
Solution : The command writes STDIN to a temporary file, runs PHP-CS-Fixer on it and then reads it back to STDOUT. Similar to what other users posted here, but standalone in your Zed config
Using PHP-CS-Fixer, this one-line has been working fine for me for a few days now. Using the scripts shared previously in this thread, my changes where often not persisting due to an issue with how Zed handles the file at
{buffer_path}
.Adjust the paths and the arguments for you needs :
{ "languages": { "PHP": { "format_on_save": "on", "formatter": { "external": { "command": "bash", "arguments": [ "-c", "cat > /tmp/zed_php_cs_fixer && php-cs-fixer fix --using-cache=no --quiet /tmp/zed_php_cs_fixer && cat /tmp/zed_php_cs_fixer" ] } } } } }
Explanation of the issue : PHP-CS-Fixer can only work on a file and doesn't support STDIN/STDOUT. Zed overwrites the file at
{buffer_path}
with stale data, so we have to use STDIN/STDOUTSolution : The command writes STDIN to a temporary file, runs PHP-CS-Fixer on it and then reads it back to STDOUT. Similar to what other users posted here, but standalone in your Zed config
Thanks for the suggestions @patricksamson @FrittenKeeZ ! If the solution I found doesn't work then I'll try yours out. What peter suggested is working for me so far: https://gist.github.com/gabrielbidula/4b8f84a02dafd242b0e1cf1d682fcaac?permalink_comment_id=5035902#gistcomment-5035902
I have another use with this, as I have to open .zed/settings.json
after updating Zed before the overrides take effect.
I ran into this exact problem with Laravel Pint, and came to this solution (basically a derivate of what @malssid is doing):
"language_overrides": {
"PHP": {
"formatter": {
"external": {
"command": "bash",
"arguments": [
"-c",
"cat > /tmp/current.pint.tmp && pint /tmp/current.pint.tmp -q && cat /tmp/current.pint.tmp && rm /tmp/current.pint.tmp"
]
}
},
"format_on_save": "on"
}
}
EDIT: I find this a bit weird, that you can't run the formatter against the file itself, since this would just run the formatter against the "previous" version of the file, not including your current edits.