dotnet / format

Home for the dotnet-format command
MIT License
1.93k stars 173 forks source link

Possible to set this up within Jetbrains Rider using the folder watch to format on save? #320

Closed MostHated closed 4 years ago

MostHated commented 5 years ago

Has anyone set this up with Rider? I have never set up a watcher from scratch as with GoLand you just tell it to format on save and it is built into the IDE, but I would imagine it should be possible to set this up to be able to format the particular file you are working on and autoformat it on file save?

I tried to see if I could get a single folder to format but I believe I might have done it incorrectly as nothing happened. When I omitted the --files and subsequent path it did indeed work, but of course it did the entire project which then forced a reimport of all of the files into Unity which would end up becoming quite time consuming on larger projects.

This is what I attempted:

dotnet-format -v diag --workspace /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Navigation_DOTS_20192.sln --files  /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assets/_instance.id/_ECS/scripts/Waypoint/Systems

I made a few purposeful changes to force the need for formatting and tried again with increased verbosity:

~ » dotnet-format -v diag --workspace /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Navigation_DOTS_20192.sln --files  /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assets/_instance.id/_ECS/scripts/Waypoint/Systems
  Formatting code files in workspace '/home/mosthated/_dev/_unity/Navigation_DOTS_20192/Navigation_DOTS_20192.sln'.
  Loading workspace.
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.Editor.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/BovineLabs.Entities.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assembly-CSharp-firstpass.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.Editor.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/BovineLabs.Entities.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assembly-CSharp-firstpass.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.Editor.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/BovineLabs.Entities.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assembly-CSharp-firstpass.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assembly-CSharp.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assembly-CSharp-Editor-firstpass.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.Editor.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/BovineLabs.Entities.csproj
  Complete in 2385ms.
  Determining formattable files.
  Complete in 188ms.
  Running formatters.
  Complete in 11ms.
  Formatted 0 of 395 files.
  Format complete in 2589ms.

This is what ended up working though and did all files.

dotnet-format -v diag --workspace /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Navigation_DOTS_20192.sln
JoeRobich commented 5 years ago

@MostHated I think this was a really interesting suggestion. It took a bit of digging but I came up with a configuration that I think will work for you.

image

Arguments:

-w $SolutionPath$ -v diag --files $FilePath$

Let me know if it works for you, -Joey

MostHated commented 5 years ago

Hey Joey, I very much appreciate the reply. I feel that should indeed be a viable solution. Unfortunately, I seem to have run into something of a roadblock. It is no fault of dotnet-format though, but I believe a result of how Unity and Rider go about obtaining their integration. Upon performing a save I receive the following output from Rider:

/home/mosthated/.dotnet/tools/dotnet-format -w /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Navigation_DOTS_20192.sln -v diag --files /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assets/_instance.id/_Scripts/Editor/CompilationTimer.cs
A fatal error occurred. The required library libhostfxr.so could not be found.
If this is a self-contained application, that library should exist in [/home/mosthated/.dotnet/tools/.store/dotnet-format/3.1.37601/dotnet-format/3.1.37601/tools/netcoreapp2.1/any/].
If this is a framework-dependent application, install the runtime in the global location [/usr/share/dotnet] or use the DOTNET_ROOT environment variable to specify the runtime location or register the runtime location in [/etc/dotnet/install_location].

Process finished with exit code 131 (interrupted by signal 3: SIGQUIT)

I have noticed that when using Rider when it has been opened via Unity, even though the setup is global within Rider, it does not utilize my configuration for using ZSH as the terminal shell, which would then come to reason that it is not acknowledging my environmental variables which would keep it from being able to properly use dotnet from my $PATH.

Trying to open the terminal within a Unity project connected Rider I get the following.

Cannot open Local Terminal
Failed to start [/bin/zsh, -i] in /home/mosthated/_dev/_unity/Navigation_DOTS_20192

I don't currently have any other dotnet projects on my pc in which I can test this, but as I mentioned, based on the output of the initial error, I believe that it should work. I am going to see if I can manually enter the necessary environmental information into my Unity projects Rider configuration and get it to work.

Thanks again, I do appreciate it! -MH

MostHated commented 5 years ago

Just wanted to throw out an update to this. I figured out my Unity issue (in case anyone else for some reason comes across the same issue), I had to start the Unity Hub as root. Then when Unity started up Rider, I guess permissions were passed to it, and then Rider was able to use zsh and get my $PATH and everything. As such, this has now started to work as... mostly expected. It feels like it takes a relatively long time to perform the actual format from the time of the command actually being issued until all is said, done, and completed even though it is filtered down to just a single file being formatted.

Just to check just now I hit tab a few times on a line of code and saved, I counted about 4-5 seconds. Considering it has to be pointed at the actual solution file, I am assuming there are a good bit of things that it has to do behind the scenes in order to perform the formatting task? My current project I am working on is an extraction from my main project, so in total the code in this current project probably only accounts for about 3-5% of the total code my game has, considering there are many large 3rd party assets and libraries that are imported into the project as active live code, not just dll's. It concerns me that it might not be viable to utilize this if the amount of time it is going to take to format a single file ends up being relative to the overall size of the project.

While I have not tested it yet with the main project to see what kind of time it ends up taking to perform the formatting, am I correct in my assumption, or should it end up taking the same amount of time regardless of the project size?

Thanks, -MH

EDIT

For some reason, only after logging out and back in starting Unity Hub as sudo began opening Unity itself as well as Rider as root, which gave a warning message, then also tried to load a new Rider profile for the root user.

So it looks like the actual solution is simply starting the Unity Hub application from the terminal. I created a zsh alias for this :

alias unity='/home/mosthated/_dev/applications/UnityHubSetup.AppImage'
scottsauber commented 5 years ago

@MostHated - I am hitting similar perf times. After experiencing Prettier (a code formatter for JavaScript), this was a bit of a bummer. Prettier runs in ~100ms for a single JS file. With dotnet format, I'm seeing ~4-6 seconds to format a pretty plain Program.cs. When I passed my csproj as my workspace, instead of the sln, that seemed to get it down to the ~4 second mark.

Here's the diag output of one of the fastest runs where I passed the csproj and a single file. It looks like the Roslyn workspace load is a big culprit.

  Formatting code files in workspace 'c:\path\to\csproj\FormatterTest.csproj'.
  Loading workspace.
  Workspace loaded in 2661ms.
  Formatting code files in project 'FormatterTest'.
  Formatting code file 'Program.cs'.
  Formatted code file 'Program.cs'.
  Formatted 1 of 9 files in 1117ms.
  Format complete.
MostHated commented 5 years ago

Here was mine just now. I certainly don't mean to sound ungrateful, but similar to you I got used to things like gofmt and dartfmt while using those languages and it is just super nice to hit save and bam, everything is great. I am quite pleased to see there is a formatter at all, lol.

  Formatting code files in workspace '/home/mosthated/_dev/_unity/Navigation_DOTS_20192/Navigation_DOTS_20192.sln'.
  Loading workspace.
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.Editor.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/BovineLabs.Entities.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assembly-CSharp.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.Editor.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/BovineLabs.Entities.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Assembly-CSharp-Editor-firstpass.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.Editor.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/BovineLabs.Entities.csproj
  Found project reference without a matching metadata reference: /home/mosthated/_dev/_unity/Navigation_DOTS_20192/Sirenix.OdinInspector.CompatibilityLayer.csproj
  Complete in 2426ms.
  Determining formattable files.
  Complete in 486ms.
  Running formatters.
  Complete in 410ms.
  Formatted code file 'WaypointComponent.cs'.
  Formatted 1 of 689 files.
  Format complete in 3425ms.
scottsauber commented 5 years ago

Same - I’m so happy there’s a formatter for .NET, because having it in JavaScript is amazing with Prettier. I just don’t even worry about formatting anymore, I just left Prettier take care of it. The possibilities of stuff that can be done is making me really excited.

RikkiGibson commented 5 years ago

I agree we should be able to do whitespace formatting very quickly for on-save scenarios, etc. A few thoughts I have:

  1. Is it potentially faster to just discover the .cs files, add them to an AdhocWorkspace and format them? (if just need to load .editorconfig we should be good, but if there's style stuff embedded in the .csproj we don't want to reinvent the process of loading that..)
  2. Is it worth it to run the formatter as a client/server similar to VBCSCompiler?

/cc @JoeRobich

scottsauber commented 5 years ago

Thanks for the response @RikkiGibson. I can try # 1 tonight when I get to a laptop (on phone ATM) and report back my findings.

For the record, I have a Lenovo X1 Extreme with 6 cores, 32GB RAM, SSD, etc. so not like I’m running some slow machine.

I have a side project I’m part of the way through that leverages dotnet format so I’d be happy to contribute in anyway possible.

MostHated commented 5 years ago

I do think it would be advantageous to have a definable exclusion list from any sort of auto-discovery. Either by directory or top-level namespace due to the previously mentioned large active code libraries that end up getting used in Unity projects which is standard source-code usually and not DLLs. I typically create a folder called 3rdParty, or similar and when I import them into my project they usually all reside in there. I don't want or need to modify those in any way as it may interfere with updating them in the future as newer versions come out, or at least cause the update process to take much longer as if the file is modified compared to the original it will end up removing and reimporting it unnecessarily.

Unfortunately, there are some asset developers who use hardcoded paths from the root of the projects assets folder which can break the asset if it is moved into a 3rdParty folder. Luckily that has become way less of an occurrence the last few years but might still happen.

Feel free to let me know as well if any testing might help out. I have multiple systems in which could be used to test. (Linux Desktop Amd Ryzen5, 32gb, nvme ssd, Linux laptop i7 87xx, 16gb nvme ssd, Windows laptop i7 34xx, 16gb, sata ssd, and a few others.)

RikkiGibson commented 5 years ago

It looks like we use the .editorconfig to check which items should be included. see #8

RikkiGibson commented 5 years ago

Sounds great @scottsauber! Look forward to seeing anything you come up with.

scottsauber commented 5 years ago

@RikkiGibson - well the AdhocWorkspace was significantly faster... to the tune of 200ms vs. 2600ms... problem is it doesn't format now, because it thinks the files contents are empty downstream... so pretty sure I'm not using AdhocWorkspace correctly.

JoeRobich commented 4 years ago

Using the Folder workspace flag (-f) should improve the performance here significantly.

Use the following args to dotnet-format - -f $SolutionPath$ -v diag --files $FilePath$

mdiluz commented 3 years ago

This is closed, but the final advice is wrong for version 4.1. The following args are now needed:

$SolutionPath$ -v diag --include $FileRelativePath$

This is due to the --folder and --files args being deprecated, and the new --include arg needing a relative path

valin0k commented 3 years ago

@JoeRobich hey, i've installed the latest version of .net 6 and can't configure C# watcher. As a program, i tried dotnet, dotnet-format, dotnet format and also a full path to dotnet /usr/local/share/dotnet/dotnet and each time I've got the following error message while saving a file

Failed to run File Watcher 'dotnet'.
The watcher has been disabled.
Error: Invalid executable

Can you help please, what is wrong with my configuration?

Снимок экрана 2021-09-04 в 13 55 05
JoeRobich commented 3 years ago

@valin0k Perhaps since you are pointing the watcher at dotnet you should add format as the first argument.

valin0k commented 3 years ago

@JoeRobich thank you! Now it works well for me, but a very small set of rules applied to the c# file. Is it possible to configure .editorconfig file to make it behave as in eslint or prettier for js? I mean at least adding a missing semicolon at the end of line

JoeRobich commented 3 years ago

@valin0k There are lots of rules that you can specify in your .editorconfig (see https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options?view=vs-2019) and we even support applying fixes for Roslyn analyzers such as StyleCop.Analyzers and Roslynator analyzers. However, I am not sure if there is a rule for missing semicolon.

valin0k commented 3 years ago

@JoeRobich thanks for your help!

glen-84 commented 1 year ago

Arguments: format whitespace $SolutionDir$ --folder --include $FileRelativePath$