XamlStyler icon indicating copy to clipboard operation
XamlStyler copied to clipboard

Project's reference to Settings.XamlStyler has less priority than solution

Open tmatz opened this issue 5 years ago • 24 comments
trafficstars

(This issue is remain of #160)

StylerPackage.GetConfigPathForItem() has the code which find the FullPath of "Settings.XamlStyler" ref in project.

  • https://github.com/Xavalon/XamlStyler/blob/765510a3b6aa9345dbd8f0bbc5825214f4941c8f/XamlStyler3.Package/StylerPackage.cs#L211

But this config-file path has less priority than solution's config-file path.

Visual Studio has "Link File" feature, which references external files as a project item.

Let think about following solution structure:

  • Root/
    • Solution.sln
    • Settings.XamlStyler (setting 1)
    • Project1/
      • Project1.csproj
      • Project1.xaml
      • Settings.XamlStyler (link to ../Settings/Settings.XamlStyler)
    • Settings/
      • Settings.XamlStyler (setting 2)

Project1.xaml should be formatted according to setting 2, but setting 1 is used currently.

tmatz avatar Dec 02 '19 07:12 tmatz

Project1.xaml should be formatted according to setting 2, but setting 1 is used currently.

I would expect Project1.xaml, in this case, to be formatted via setting 1, since it is the the first configuration in up hierarchy. setting 2 is inside of a sub-directory. Am I missing something in your example?

grochocki avatar Dec 02 '19 07:12 grochocki

IMO, detailed and explicitly specified setting should have higher priority.

In example case, (1) project setting is more detailed than solution, and (2) it is specified explicitly.

It seems design decision.

tmatz avatar Dec 02 '19 07:12 tmatz

I have a similar issue.

My solution structure is as follows:

  • Root
    • Build
      • Solution.sln
      • Settings.XamlStyler (setting 1)
    • Project1
      • Project1.csproj
      • Settings.XamlStyler (setting 2)
    • Project2
      • Project2.csproj

In this case, Project1 is formatted according to setting 2, which is what I expect. ✔️ Project2 is formatted according to XamlStyler default settings, but I would expect it to be formatted according to setting 1. ❌

It seems, setting 1 is not discovered at all.

The documentation explains that the settings file is searched also in the directory of the solution file: Alternatively, put your external configuration inside a "Settings.XamlStyler" file in any directory up through your solution directory and this configuration will take precedence.

I'm using Visual Studio 2019 (16.4.2) and XAML Styler 3.2.5.

schlotter avatar Dec 18 '19 12:12 schlotter

@schlotter If there are two solutions both references Projects2 and each have different Settings.XamlStyler, Xaml files in Project2 will be re-formatted differently according to the active solution. It seems problematic.

tmatz avatar Dec 19 '19 15:12 tmatz

Alternatively, put your external configuration inside a "Settings.XamlStyler" file in any directory up through your solution directory and this configuration will take precedence.

The documentation does not make it as clear as it could be here, so I added emphasis to draw attention to how it only looks up through folder hierarchy. In your example, the build directory is a sibling to Project2, so it would only look in root, where a configuration file does not exist.

grochocki avatar Dec 20 '19 23:12 grochocki

related: #154 SearchToDriveRoot Feature

tmatz avatar Dec 21 '19 00:12 tmatz

How about this priority rule ?

(Above has lower priority)

  • Visual Studio
  • Solution Directory (if Solution directory is not a ancestor of project directory) (this seems not provide a clear benefit. But when SearchToDriveRoot is false, this rule allows solution wide common setting even if project is outside the solution directory.)
  • Drive Root
    • Directories ... (usually include Solution Directory)
      • Project Directory
        • Project's reference To Settings.XamlStyler (treats as same as setting in project directory)
        • Directories ...
          • File's Directory
            • File.xaml

(Below has higher priority)

tmatz avatar Dec 21 '19 05:12 tmatz

@schlotter If there are two solutions both references Projects2 and each have different Settings.XamlStyler, Xaml files in Project2 will be re-formatted differently according to the active solution. It seems problematic.

I agree, that is not optimal.

How about this priority rule ?

What you suggest looks good to me!

To double-check I understand it correctly, here is an example:

  • Root
    • Settings.XamlStyler (setting 1)
    • Build
      • Solution.sln
      • Settings.XamlStyler (setting 2)
    • Project1
      • Project1.csproj
      • Settings.XamlStyler (setting 3)
    • Project2
      • Project2.csproj

In this case, setting 1 has the highest priority. Setting 1 will be used by Project1.csproj and Project2.csproj. Setting 2 has second highest priority and setting 3 has third highest priority. Setting 2 and setting 3 will not be used, as setting 1 takes precedence.

This will work for well for me, as I will ensure there is only one Settings.XamlStyler somewhere close to the root of the repository which is to be used by all projects.

Thank you!

schlotter avatar Jan 03 '20 12:01 schlotter

How about this priority rule?

@tmatz I agree with the hierarchy here, but I don't think @schlotter's interpretation is quite right. The "closest" configuration in the up-hierarchy should take precedence. That allows you to specify a default solution-wide configuration, while overriding it for specific projects or directories.

Complicating the example a bit more...

  • Root
    • Settings.XamlStyler (setting 1)
    • Build
      • Solution.sln
      • Settings.XamlStyler (setting 2)
    • Project1
      • MainPage1.xaml
      • Settings.XamlStyler (setting 3)
        • Project1Control.xaml
    • Project2
      • MainPage2.xaml
        • Project2Control.xmal
        • Settings.XamlStyler (setting 4)
    • Project3
      • MainPage3.xaml
        • Project3Control.xmal

Setting 1 is not applied anywhere Setting 2 applies to MainPage2.xaml, MainPage3.xaml, and Project3Contorl.xaml Setting 3 applies to MainPage1.xaml and Project1Control.xaml Setting 4 applies to Project2Control.xaml

If Setting 2 was removed, then Setting 1 would apply to MainPage2.xaml, MainPage3.xaml, and Project3Contorl.xaml.

If Setting 2, Setting 3, and Setting 4 were all removed, then Setting 1 would apply to all files.

grochocki avatar Jan 06 '20 06:01 grochocki

@schlotter @grochocki My proposal is different from both of your interpretations.

As @grochocki says, the "closest" configuration in the up-hierarchy should take precedence. By this rule, configuration will be selected as following:

  • Root/
    • Settings.XamlStyler (setting 1)
    • Build/
      • Solution.sln
      • Settings.XamlStyler (setting 2)
    • Project1/
      • Settings.XamlStyler (setting 3)
      • MainPage1.xaml (uses setting 3)
      • sub/
        • Project1Control.xaml (uses setting 3)
    • Project2/
      • MainPage2.xaml (uses setting 1)
      • sub/
        • Settings.XamlStyler (setting 4)
        • Project2Control.xmal (uses setting 4)
    • Project3/
      • MainPage3.xaml (uses setting 1)
      • sub/
        • Project3Control.xmal (uses setting 1)

In this example, the solution directory is not in a up-hierarchy of any .xaml file. And, there is setting 1 which is in up-hierarchy of all .xaml files. So setting 2 is never used.

This is current implementation if SearchToDriveRoot option is true(~~default~~ wrong. default is false).

tmatz avatar Jan 06 '20 08:01 tmatz

@grochocki To obey your interpretation, priority of solution directory should be inserted between up-hierarchy of .xaml file. Could you describe where is the insertion point?

tmatz avatar Jan 06 '20 08:01 tmatz

In this example, the solution directory is not in a up-hierarchy of any .xaml file. And, there is setting 1 which is in up-hierarchy of all .xaml files. So setting 2 is never used.

I am fine with this. IMHO, trying to include the solution directory, if it is not a direct ancestor in folder up-hierarchy, does not provide a clear benefit.

This is current implementation if SearchToDriveRoot option is true(default).

If this is the case, then I think we can close this as by design. Admittedly, I do not have our mock solution hierarchy to actually test live. A documentation update would help clarify this behavior, though.

grochocki avatar Jan 06 '20 08:01 grochocki

In this example, the solution directory is not in a up-hierarchy of any .xaml file. And, there is setting 1 which is in up-hierarchy of all .xaml files. So setting 2 is never used.

This is current implementation if SearchToDriveRoot option is true(default).

I will try that again tomorrow. In my tests finding a setting like setting 1 did not work, but I recall Settings.XamlStyler was four or five levels up from the project files...

I think there was no way of immediately seeing exactly which Settings.XamlStyler was loaded, was it?

schlotter avatar Jan 06 '20 08:01 schlotter

I think there was no way of immediately seeing exactly which Settings.XamlStyler was loaded, was it?

Unfortunately, not. I test this using exaggerated indent sizes for different configuration files so I can quickly tell which one is being applied (e.g., 2, 20, 40, etc.).

grochocki avatar Jan 06 '20 08:01 grochocki

I will try that again tomorrow. In my tests finding a setting like setting 1 did not work, but I recall Settings.XamlStyler was four or five levels up from the project files...

Oh, maybe I misunderstand? I will try that tomorrow too. (It should be a new feature of 3.2001.0)

tmatz avatar Jan 06 '20 08:01 tmatz

@grochocki

IMHO, trying to include the solution directory, if it is not a direct ancestor in folder up-hierarchy, does not provide a clear benefit.

I agree.

tmatz avatar Jan 06 '20 08:01 tmatz

@grochocki Main theme of this issue is the priority of project's reference.

tmatz avatar Jan 06 '20 08:01 tmatz

Main theme of this issue is the priority of project's reference.

Right -- I suppose the question is whether there is a clear benefit to supporting linked configurations or whether the guidance should be just include the file directly (or in up-hierarchy). While I understand it is possible, is there any clear benefit to the folder structure in your original issue submission (with the linked settings file)?

grochocki avatar Jan 06 '20 09:01 grochocki

is there any clear benefit to the folder structure in your original issue submission (with the linked settings file)?

I have never used the linked settings file feature. But when I knew this feature, I think this is useful for a situation like following:

  • Solution/
    • Settings.XamlStyler (setting 1 for default setting)
    • Project1/
    • Project2/
    • ...
    • Project9/
      • Settings.XamlStyler (setting 2 for a group of some projects)
    • Project9.Sub1/
      • Project9.Sub1.csproj (has linked settings file points to setting 2)
    • Project9.Sub2/
      • Project9.Sub2.csproj (has linked settings file points to setting 2)

Setting 1 applies to most projects (Project1, Project2, ...). Setting 2 applies to some exceptional projects (Project9, Project9.Sub1, and Project9.Sub2). This setting is also wanted to be shared for ease of maintainance.

But in the current implementation, settings 1 applies to Project9.Sub1 and Project9.Sub2.

Current priority rule is like this:

(Above has lower priority)

  • Visual Studio
  • Project's linked settings file
  • Drive Root
    • Directories ... (usually include Solution Directory)
      • Project Directory
        • Directories ...
          • Xaml File's Directory

(Below has higher priority)

tmatz avatar Jan 06 '20 13:01 tmatz

I had misunderstood until now. SearchToDriveRoot option is default false. (Of course. this is a very big change)

When SearchToDriveRoot option is false, the configurations are selected as follows:

  • Root/
    • Settings.XamlStyler (setting 1 not applied to anyone)
    • Build/
      • Solution.sln
      • Settings.XamlStyler (setting 2 not applied to anyone)
    • Project1/
      • Settings.XamlStyler (setting 3)
      • MainPage1.xaml (uses setting 3)
      • sub/
        • Project1Control.xaml (uses setting 3)
    • Project2/
      • MainPage2.xaml (uses vs option setting)
      • sub/
        • Settings.XamlStyler (setting 4)
        • Project2Control.xmal (uses setting 4)
    • Project3/
      • MainPage3.xaml (uses vs option setting)
      • sub/
        • Project3Control.xmal (uses vs option setting)
    • Project4/
      • Project4.csproj (has linked settings file point to setting 5)
      • MainPage4.xaml (uses setting 5)
    • Settings/
      • Settings.XamlStyler (setting 5)

Both setting 1 and setting 2 are not applied to anyone. Since the project directory is outside the solution directory, configuration files are searched up to the project directory.

tmatz avatar Jan 07 '20 03:01 tmatz

I think it should be possible to retrieve the solution directory (i.e., Build/). If so, even if SearchToDriveRoot is false, that would allow Setting 2 to be applied.

Alternatively, we could consider updating the SearchToDriveRoot default to true, but I was originally opposed to that, because it would mean that for anyone not using a configuration, we would always be crawling to root and turning up empty.

grochocki avatar Jan 07 '20 05:01 grochocki

As a side note, one interesting behavior of the current implementation is that if the project and solution are on different drives, the configuration file will only be searched up to the project directory, even if the SearchToDriveRoot option is true.

tmatz avatar Jan 07 '20 08:01 tmatz

I think it should be possible to retrieve the solution directory (i.e., Build/). If so, even if SearchToDriveRoot is false, that would allow Setting 2 to be applied.

Alternatively, we could consider updating the SearchToDriveRoot default to true, but I was originally opposed to that, because it would mean that for anyone not using a configuration, we would always be crawling to root and turning up empty.

Arguments in favor of adding SearchToDriveRoot default to true:

  • .editorconfig is by default searched up to the root
  • ReSharper.DotSettings of ReSharper is by default searched up to the root

Searching by default up to the root is useful to ensure development teams (working with many solutions in different directories, but with a common repository and thus common repository root) use consistent settings.

At the moment, I can only ensure that by asking everyone to set SearchToDriveRoot to true (which never works) or by accepting that this does not work and placing Settings.XamlStyler in many locations all over the repo and keeping the files in sync.

Thus, I would prefer the simpler approach which is to set SearchToDriveRoot to true by default.

In this example, the solution directory is not in a up-hierarchy of any .xaml file. And, there is setting 1 which is in up-hierarchy of all .xaml files. So setting 2 is never used. This is current implementation if SearchToDriveRoot option is true(default).

I will try that again tomorrow. In my tests finding a setting like setting 1 did not work, but I recall Settings.XamlStyler was four or five levels up from the project files...

It was already confirmed above that SearchToDriveRoot is false by default. I have just verified that again with XamlStyler 3.2001.0.

schlotter avatar Jan 07 '20 08:01 schlotter

As a side note, one interesting behavior of the current implementation is that if the project and solution are on different drives, the configuration file will only be searched up to the project directory, even if the SearchToDriveRoot option is true.

Hmm. This feels like an extreme edge case, though. Not sure it is worth optimizing for this scenario.

Arguments in favor of adding SearchToDriveRoot default to true...

Seems reasonable enough. I am fine with changing the default here to true assuming the behavior is as described in @tmatz's comment.

grochocki avatar Jan 07 '20 09:01 grochocki