dprint / dprint-plugin-exec

Formatting plugin for dprint that formats code via other formatting CLI tools.
MIT License
21 stars 1 forks source link

`stdout` option for the tools that directly write to the file #26

Open aminya opened 1 year ago

aminya commented 1 year ago

Some formatter tools like black from Python have no option for printing to the stdout. There should be an option so that those tools can directly write to the file without warnings.

han-tyumi commented 10 months ago

I'm also facing this with F#'s Fantomas.

adaliszk commented 2 months ago

Similar with PHP's PHP-CS-Fixer

RafaelKr commented 6 days ago

In my Symfony project (PHP) I built a little wrapper script to overcome this limitation. It's not nice, but it works for now.

I created the file bin/dprint-stdout-wrapper.sh

#!/usr/bin/env bash

# Currently dprint doesn't provide a way to use commands which modify the
# file directly instead of printing the result to stdout
# see https://github.com/dprint/dprint-plugin-exec/issues/26
#
# Therefore we use this little wrapper script which we can call like this
# bin/dprint-stdout-wrapper.sh vendor/bin/php-cs-fixer fix {{file_path}}
#
# The last argument MUST BE the file path as it first calls the command and
# then uses cat to print that path to a file

# https://unix.stackexchange.com/a/612122
FILE_PATH="${!#}"  # see man bash, search for "indirect expansion"

# this "pops" the file path from the argument list which we use via $@
set -- "${@:1:$#-1}"

$@ $FILE_PATH >&2 && cat $FILE_PATH

Now I can use the following config in my dprint.json to run PHP-CS-Fixer and Twig-CS-Fixer:

{
    // ...
    "markup": {
        "associations": [
            "!**/*.twig"
        ]
    },
    "exec": {
        "cwd": "${configDir}",

        "commands": [
            {
                "command": "bin/dprint-stdout-wrapper.sh vendor/bin/php-cs-fixer fix {{file_path}}",
                "exts": ["php"]
            },
            {
                "command": "bin/dprint-stdout-wrapper.sh vendor/bin/twig-cs-fixer lint --report null --fix {{file_path}}",
                "exts": ["twig"]
            }
        ]
    },
    "excludes": [
        "**/node_modules",
        "**/*-lock.json",
        "assets/vendor/*",
        "assets/**/controllers.json",
        "composer.json",
        "public/assets/*",
        "package.json",
        "README.md"
    ],
    "plugins": [
        // ...
        "https://plugins.dprint.dev/exec-0.5.0.json@8d9972eee71fa1590e04873540421f3eda7674d0f1aae3d7c788615e7b7413d0"
    ]
}

Edit: added twig-cs-fixer command

Edit 2: >&2 was required to pipe stdout to stderr

RafaelKr commented 6 days ago

@adaliszk I just updated my comment. See "Edit 2"

RafaelKr commented 6 days ago

I just noticed one downside: When running dprint fmt the fix is still applied to the file.

So we also would need dprint-plugin-exec to provide us with the current mode, maybe via a command template {{mode}}. Then in our script we can decide if we want to use fix or check (or --dry-run, etc)

adaliszk commented 6 days ago

Yeah, I was thinking about making a wrapper like that, but the issue is that there would be two separate reads and writes for the same file. At the moment, I am exploring the option of changing the PHP-CS-Fixer and, in extension, Laravel Pint to have a print mode instead.

Luckily, the stdin option is already there, so it's easy to argue for a stdout mode to let any external tool handle the filesystem.

RafaelKr commented 3 days ago

Yes, that's really not very elegant, just a workaround. Also I now used a similar wrapper for Twig-CS-Fixer and then running prettier with the Plugin for Tailwind automatic class sorting on the file (https://github.com/ttskch/prettier-plugin-tailwindcss-anywhere)

After also adding https://daisyui.com/ it was writing log output from daisyUI to my twig files. I now set an env var in my script which disables logging from the tailwind.config.js – also not very nice.

RafaelKr commented 2 days ago

Okay, my colleague had issues in VS Code because the command wrote to the file multiple times. I now updated my wrapper script to use a temporary file instead.

bin/dprint-stdout-wrapper.sh

#!/usr/bin/env bash

# Currently dprint doesn't provide a way to use commands which modify the
# file directly instead of printing the result to stdout
# see https://github.com/dprint/dprint-plugin-exec/issues/26
#
# Therefore we use this little wrapper script which we can call like this
# bin/dprint-stdout-wrapper.sh vendor/bin/php-cs-fixer fix
#
# dprint passes the input via stdin which we write to a temporary file.
# Then we apply the formatting to the temporary file and write the result
# to stdout. dprint then writes the output back to the input file.

TEMP_FILE=$(mktemp)

# read stdin to temporary file
cat - > $TEMP_FILE

function cleanup {
  rm "$TEMP_FILE"
}
# make sure the temporary file is removed on exit, even in error cases
trap cleanup EXIT

$@ $TEMP_FILE >&2 && cat $TEMP_FILE

To make it work for twig files in VS Code my workaround is even worse, but works now:

bin/fix-twig.sh

#!/usr/bin/env bash

# Currently dprint doesn't provide a way to use commands which modify the
# file directly instead of printing the result to stdout
# see https://github.com/dprint/dprint-plugin-exec/issues/26
#
# Therefore we use this little wrapper script which we can call like this
# bin/fix-twig.sh {{file_path}}
#
# dprint passes the input via stdin which we write to a temporary file.
# Then we apply the formatting to the temporary file and write the result
# to stdout. dprint then writes the output back to the input file.

# We use the file path for prettier to determine the correct parser
# https://prettier.io/docs/en/options.html#file-path
FILE_PATH="$1"

TEMP_FILE=$(mktemp)
# read stdin to temporary file
cat - > $TEMP_FILE

function cleanup {
    rm -f "$TEMP_FILE"
}
# make sure the temporary file is removed on exit, even in error cases
trap cleanup EXIT

CURRENT_SCRIPT_DIR_NAME=$(dirname "${BASH_SOURCE[0]}")

vendor/bin/twig-cs-fixer lint --report null --fix $TEMP_FILE

cat $TEMP_FILE | \
  DISABLE_DAISY_LOGS=1 node_modules/.bin/prettier \
    --config "$CURRENT_SCRIPT_DIR_NAME/.prettierrc" \
    --stdin-filepath "$FILE_PATH"

The .prettierrc file is taken from https://github.com/ttskch/prettier-plugin-tailwindcss-anywhere?tab=readme-ov-file#usage

My dprint.json looks like:

{
    // ...
    "markup": {
        "associations": [
            "!**/*.twig"
        ]
    },
    "exec": {
        "cwd": "${configDir}",

        "commands": [
            {
                "command": "bin/dprint-stdout-wrapper.sh vendor/bin/php-cs-fixer fix",
                "exts": ["php"]
            },
            {
                "command": "bin/fix-twig.sh {{file_path}}",
                "exts": ["twig"]
            }
        ]
    },
    "excludes": [
        "**/node_modules",
        "**/*-lock.json",
        "assets/vendor/*",
        "assets/**/controllers.json",
        "composer.json",
        "public/assets/*",
        "package.json"
    ],
    "plugins": [
        // ...
        "https://plugins.dprint.dev/exec-0.5.0.json@8d9972eee71fa1590e04873540421f3eda7674d0f1aae3d7c788615e7b7413d0"
    ]
}

Edit: simplified bin/fix-twig.sh as https://github.com/ttskch/prettier-plugin-tailwindcss-anywhere/issues/2 got fixed.

RafaelKr commented 21 hours ago

I just opened: