未验证 提交 c40b14c7 编写于 作者: M Manish Vasani 提交者: GitHub

Merge pull request #39127 from mavasani/SolutionItemEditorConfig

Enable detection and addition of solution level .editorconfig as solu…
......@@ -185,9 +185,18 @@ private async Task<Solution> ConfigureAsync()
// Compute the updated text for analyzer config document.
var newText = GetNewAnalyzerConfigDocumentText(originalText, editorConfigDocument);
return newText != null
? solution.WithAnalyzerConfigDocumentText(editorConfigDocument.Id, newText)
: solution;
if (newText == null)
{
return solution;
}
// Add the newly added analyzer config document as a solution item.
// The analyzer config document is not yet created, so we just mark the file
// path for tracking and add it as a solution item whenever the file gets created by the code fix application.
var service = _project.Solution.Workspace.Services.GetService<IAddSolutionItemService>();
service?.TrackFilePathAndAddSolutionItemWhenFileCreated(editorConfigDocument.FilePath);
return solution.WithAnalyzerConfigDocumentText(editorConfigDocument.Id, newText);
}
private AnalyzerConfigDocument FindOrGenerateEditorConfig()
......@@ -198,7 +207,32 @@ private AnalyzerConfigDocument FindOrGenerateEditorConfig()
return null;
}
return _project.GetOrCreateAnalyzerConfigDocument(analyzerConfigPath);
if (_project.Solution?.FilePath == null)
{
// Project has no solution or solution without a file path.
// Add analyzer config to just the current project.
return _project.GetOrCreateAnalyzerConfigDocument(analyzerConfigPath);
}
// Otherwise, add analyzer config document to all applicable projects for the current project's solution.
AnalyzerConfigDocument analyzerConfigDocument = null;
var analyzerConfigDirectory = PathUtilities.GetDirectoryName(analyzerConfigPath);
var currentSolution = _project.Solution;
foreach (var projectId in _project.Solution.ProjectIds)
{
var project = currentSolution.GetProject(projectId);
if (project?.FilePath?.StartsWith(analyzerConfigDirectory) == true)
{
var addedAnalyzerConfigDocument = project.GetOrCreateAnalyzerConfigDocument(analyzerConfigPath);
if (addedAnalyzerConfigDocument != null)
{
analyzerConfigDocument ??= addedAnalyzerConfigDocument;
currentSolution = addedAnalyzerConfigDocument.Project.Solution;
}
}
}
return analyzerConfigDocument;
}
private static ImmutableArray<(string optionName, string currentOptionValue, string currentSeverity, bool isPerLanguage)> GetCodeStyleOptionValuesForDiagnostic(
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.CodeFixes
{
internal interface IAddSolutionItemService : IWorkspaceService
{
/// <summary>
/// Tracks the given file path of a non-existent file and whenever a new file with this file path is created,
/// it adds it as a solution item.
/// NOTE: <paramref name="filePath"/> is expected to be an absolute path of a file that does not yet exist.
/// </summary>
void TrackFilePathAndAddSolutionItemWhenFileCreated(string filePath);
/// <summary>
/// Adds a file at the given path as a solution item.
/// NOTE: <paramref name="filePath"/> is expected to be an absolute path of an existing file.
/// </summary>
Task AddSolutionItemAsync(string filePath, CancellationToken cancellationToken);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using EnvDTE;
using EnvDTE80;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Extensions;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.Shell;
using Roslyn.Utilities;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
[Export, Shared]
internal partial class AnalyzerConfigDocumentAsSolutionItemHandler : IDisposable
{
private static readonly string LocalRegistryPath = $@"Roslyn\Internal\{nameof(AnalyzerConfigDocumentAsSolutionItemHandler)}\";
private static readonly Option<bool> NeverShowAgain = new Option<bool>(nameof(AnalyzerConfigDocumentAsSolutionItemHandler), nameof(NeverShowAgain),
defaultValue: false, storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeverShowAgain)));
private readonly VisualStudioWorkspace _workspace;
private readonly IThreadingContext _threadingContext;
private DTE? _dte;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public AnalyzerConfigDocumentAsSolutionItemHandler(
VisualStudioWorkspace workspace,
IThreadingContext threadingContext)
{
_workspace = workspace;
_threadingContext = threadingContext;
_workspace.WorkspaceChanged += OnWorkspaceChanged;
}
public void Initialize(IServiceProvider serviceProvider)
{
_dte = (DTE)serviceProvider.GetService(typeof(DTE));
}
void IDisposable.Dispose()
{
_workspace.WorkspaceChanged -= OnWorkspaceChanged;
}
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
{
// Check if a new analyzer config document was added and we have a non-null DTE instance.
if (e.Kind != WorkspaceChangeKind.AnalyzerConfigDocumentAdded ||
_dte == null)
{
return;
}
// Check if added analyzer config document is at the root of the current solution.
var analyzerConfigDocumentFilePath = e.NewSolution.GetAnalyzerConfigDocument(e.DocumentId)?.FilePath;
var analyzerConfigDirectory = PathUtilities.GetDirectoryName(analyzerConfigDocumentFilePath);
var solutionDirectory = PathUtilities.GetDirectoryName(e.NewSolution.FilePath);
if (analyzerConfigDocumentFilePath == null ||
analyzerConfigDirectory == null ||
analyzerConfigDirectory != solutionDirectory)
{
return;
}
// Check if user has explicitly disabled the suggestion to add newly added analyzer config document as solution item.
if (_workspace.Options.GetOption(NeverShowAgain))
{
return;
}
// Kick off a task to show info bar to make it a solution item.
Task.Run(async () =>
{
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync();
var solution = (Solution2)_dte.Solution;
if (VisualStudioAddSolutionItemService.TryGetExistingSolutionItemsFolder(solution, analyzerConfigDocumentFilePath, out _, out var hasExistingSolutionItem) &&
hasExistingSolutionItem)
{
return;
}
var infoBarService = _workspace.Services.GetRequiredService<IInfoBarService>();
infoBarService.ShowInfoBarInGlobalView(
ServicesVSResources.A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item,
GetInfoBarUIItems().ToArray());
});
return;
// Local functions
IEnumerable<InfoBarUI> GetInfoBarUIItems()
{
// Yes - add editorconfig solution item.
yield return new InfoBarUI(
title: ServicesVSResources.Yes,
kind: InfoBarUI.UIKind.Button,
action: AddEditorconfigSolutionItem,
closeAfterAction: true);
// No - do not add editorconfig solution item.
yield return new InfoBarUI(
title: ServicesVSResources.No,
kind: InfoBarUI.UIKind.Button,
action: () => { },
closeAfterAction: true);
// Don't show the InfoBar again link
yield return new InfoBarUI(title: ServicesVSResources.Never_show_this_again,
kind: InfoBarUI.UIKind.Button,
action: () => _workspace.Options = _workspace.Options.WithChangedOption(NeverShowAgain, true),
closeAfterAction: true);
}
void AddEditorconfigSolutionItem()
{
var addSolutionItemService = _workspace.Services.GetRequiredService<IAddSolutionItemService>();
addSolutionItemService.AddSolutionItemAsync(analyzerConfigDocumentFilePath, CancellationToken.None).Wait();
}
}
}
}
......@@ -14,12 +14,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
internal sealed class FileChangeTracker : IVsFreeThreadedFileChangeEvents2, IDisposable
{
private const _VSFILECHANGEFLAGS FileChangeFlags = _VSFILECHANGEFLAGS.VSFILECHG_Time | _VSFILECHANGEFLAGS.VSFILECHG_Add | _VSFILECHANGEFLAGS.VSFILECHG_Del | _VSFILECHANGEFLAGS.VSFILECHG_Size;
private const _VSFILECHANGEFLAGS DefaultFileChangeFlags = _VSFILECHANGEFLAGS.VSFILECHG_Time | _VSFILECHANGEFLAGS.VSFILECHG_Add | _VSFILECHANGEFLAGS.VSFILECHG_Del | _VSFILECHANGEFLAGS.VSFILECHG_Size;
private static readonly AsyncLazy<uint?> s_none = new AsyncLazy<uint?>(ct => null, cacheResult: true);
private readonly IVsFileChangeEx _fileChangeService;
private readonly string _filePath;
private readonly _VSFILECHANGEFLAGS _fileChangeFlags;
private bool _disposed;
/// <summary>
......@@ -48,10 +49,11 @@ internal sealed class FileChangeTracker : IVsFreeThreadedFileChangeEvents2, IDis
/// </summary>
private static readonly object s_lastBackgroundTaskGate = new object();
public FileChangeTracker(IVsFileChangeEx fileChangeService, string filePath)
public FileChangeTracker(IVsFileChangeEx fileChangeService, string filePath, _VSFILECHANGEFLAGS fileChangeFlags = DefaultFileChangeFlags)
{
_fileChangeService = fileChangeService;
_filePath = filePath;
_fileChangeFlags = fileChangeFlags;
_fileChangeCookie = s_none;
}
......@@ -105,7 +107,7 @@ public void StartFileChangeListeningAsync()
{
try
{
return await ((IVsAsyncFileChangeEx)_fileChangeService).AdviseFileChangeAsync(_filePath, FileChangeFlags, this).ConfigureAwait(false);
return await ((IVsAsyncFileChangeEx)_fileChangeService).AdviseFileChangeAsync(_filePath, _fileChangeFlags, this).ConfigureAwait(false);
}
catch (Exception e) when (ReportException(e))
{
......@@ -116,7 +118,7 @@ public void StartFileChangeListeningAsync()
try
{
Marshal.ThrowExceptionForHR(
_fileChangeService.AdviseFileChange(_filePath, (uint)FileChangeFlags, this, out var newCookie));
_fileChangeService.AdviseFileChange(_filePath, (uint)_fileChangeFlags, this, out var newCookie));
return newCookie;
}
catch (Exception e) when (ReportException(e))
......@@ -144,7 +146,7 @@ private static bool ReportException(Exception e)
return true;
}
public void StopFileChangeListening()
private void StopFileChangeListening()
{
if (_disposed)
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Concurrent;
using System.Composition;
using System.IO;
using System.Threading;
using EnvDTE;
using EnvDTE80;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
[Export]
[ExportWorkspaceService(typeof(IAddSolutionItemService)), Shared]
internal partial class VisualStudioAddSolutionItemService : IAddSolutionItemService
{
private const string SolutionItemsFolderName = "Solution Items";
private readonly object _gate = new object();
private readonly IThreadingContext _threadingContext;
private readonly ConcurrentDictionary<string, FileChangeTracker> _fileChangeTrackers;
private DTE? _dte;
private IVsFileChangeEx? _fileChangeService;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public VisualStudioAddSolutionItemService(
IThreadingContext threadingContext)
{
_threadingContext = threadingContext;
_fileChangeTrackers = new ConcurrentDictionary<string, FileChangeTracker>(StringComparer.OrdinalIgnoreCase);
}
public void Initialize(IServiceProvider serviceProvider)
{
_dte = (DTE)serviceProvider.GetService(typeof(DTE));
_fileChangeService = (IVsFileChangeEx)serviceProvider.GetService(typeof(SVsFileChangeEx));
}
public void TrackFilePathAndAddSolutionItemWhenFileCreated(string filePath)
{
if (_fileChangeService != null &&
PathUtilities.IsAbsolute(filePath) &&
FileExistsWithGuard(filePath) == false)
{
// Setup a new file change tracker to track file path and
// add newly created file as solution item.
_fileChangeTrackers.GetOrAdd(filePath, CreateTracker);
}
return;
// Local functions
FileChangeTracker CreateTracker(string filePath)
{
var tracker = new FileChangeTracker(_fileChangeService, filePath, _VSFILECHANGEFLAGS.VSFILECHG_Add);
tracker.UpdatedOnDisk += OnFileAdded;
tracker.StartFileChangeListeningAsync();
return tracker;
}
}
private void OnFileAdded(object sender, EventArgs e)
{
var tracker = (FileChangeTracker)sender;
var filePath = tracker.FilePath;
_fileChangeTrackers.TryRemove(filePath, out _);
AddSolutionItemAsync(filePath, CancellationToken.None).Wait();
tracker.UpdatedOnDisk -= OnFileAdded;
tracker.Dispose();
}
public async Task AddSolutionItemAsync(string filePath, CancellationToken cancellationToken)
{
if (_dte == null)
{
return;
}
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
lock (_gate)
{
var solution = (Solution2)_dte.Solution;
if (!TryGetExistingSolutionItemsFolder(solution, filePath, out var solutionItemsFolder, out var hasExistingSolutionItem))
{
solutionItemsFolder = solution.AddSolutionFolder("Solution Items");
}
if (!hasExistingSolutionItem &&
solutionItemsFolder != null &&
FileExistsWithGuard(filePath) == true)
{
solutionItemsFolder.ProjectItems.AddFromFile(filePath);
solution.SaveAs(solution.FileName);
}
}
}
private static bool? FileExistsWithGuard(string filePath)
{
try
{
return File.Exists(filePath);
}
catch (IOException)
{
return null;
}
}
public static bool TryGetExistingSolutionItemsFolder(Solution2 solution, string filePath, out EnvDTE.Project? solutionItemsFolder, out bool hasExistingSolutionItem)
{
solutionItemsFolder = null;
hasExistingSolutionItem = false;
var fileName = PathUtilities.GetFileName(filePath);
foreach (Project project in solution.Projects)
{
if (project.Kind == EnvDTE.Constants.vsProjectKindSolutionItems &&
project.Name == SolutionItemsFolderName)
{
solutionItemsFolder = project;
foreach (ProjectItem projectItem in solutionItemsFolder.ProjectItems)
{
if (fileName == projectItem.Name)
{
hasExistingSolutionItem = true;
break;
}
}
return true;
}
}
return false;
}
}
}
......@@ -8,7 +8,6 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion.Log;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Experiments;
......@@ -124,6 +123,10 @@ protected override async Task LoadComponentsAsync(CancellationToken cancellation
// the appropriate task scheduler to report events on.
this.ComponentModel.GetService<MiscellaneousFilesWorkspace>();
// Load and initialize the services detecting and adding new analyzer config documents as solution item.
this.ComponentModel.GetService<AnalyzerConfigDocumentAsSolutionItemHandler>().Initialize(this);
this.ComponentModel.GetService<VisualStudioAddSolutionItemService>().Initialize(this);
LoadAnalyzerNodeComponents();
LoadComponentsBackgroundAsync(cancellationToken).Forget();
......
......@@ -125,6 +125,16 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?.
/// </summary>
internal static string A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item {
get {
return ResourceManager.GetString("A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_" +
"to_make_it_a_solution_item", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A new namespace will be created.
/// </summary>
......
......@@ -1323,4 +1323,7 @@ I agree to all of the foregoing:</value>
<data name="Updating_severity" xml:space="preserve">
<value>Updating severity</value>
</data>
<data name="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item" xml:space="preserve">
<value>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</value>
</data>
</root>
\ No newline at end of file
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="cs" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Vytvoří se nový obor názvů.</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="de" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Ein neuer Namespace wird erstellt.</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="es" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Se creará un espacio de nombres</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="fr" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Un espace de noms va être créé</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="it" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Verrà creato un nuovo spazio dei nomi</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="ja" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">新しい名前空間が作成されます</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="ko" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">새 네임스페이스가 만들어집니다.</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="pl" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Zostanie utworzona nowa przestrzeń nazw</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="pt-BR" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Um namespace será criado</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="ru" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Будет создано пространство имен</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="tr" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">Yeni bir ad alanı oluşturulacak</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="zh-Hans" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">将创建一个新的命名空间</target>
......
......@@ -2,6 +2,11 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="zh-Hant" original="../ServicesVSResources.resx">
<body>
<trans-unit id="A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item">
<source>A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</source>
<target state="new">A new .editorconfig file was detected at the root of your solution. Would you like to make it a solution item?</target>
<note />
</trans-unit>
<trans-unit id="A_new_namespace_will_be_created">
<source>A new namespace will be created</source>
<target state="translated">將會建立新的命名空間</target>
......
......@@ -89,14 +89,16 @@ public static async Task<VersionStamp> GetVersionAsync(this Project project, Can
}
}
// Did not find any existing .editorconfig, so create one at root of the project.
if (!PathUtilities.IsAbsolute(project.FilePath))
// Did not find any existing .editorconfig, so create one at root of the solution, if one exists.
// If project is not part of a solution, then use project path.
var solutionOrProjectFilePath = project.Solution?.FilePath ?? project.FilePath;
if (!PathUtilities.IsAbsolute(solutionOrProjectFilePath))
{
return null;
}
var projectFilePath = PathUtilities.GetDirectoryName(project.FilePath);
return PathUtilities.CombineAbsoluteAndRelativePaths(projectFilePath, ".editorconfig");
var solutionOrProjectDirectoryPath = PathUtilities.GetDirectoryName(solutionOrProjectFilePath);
return PathUtilities.CombineAbsoluteAndRelativePaths(solutionOrProjectDirectoryPath, ".editorconfig");
}
public static AnalyzerConfigDocument? TryGetExistingAnalyzerConfigDocumentAtPath(this Project project, string analyzerConfigPath)
......
......@@ -193,7 +193,7 @@ private static Project CreateProject(ProjectId projectId, Solution solution)
}
/// <summary>
/// Gets the additional document in this solution with the specified document ID.
/// Gets the analyzer config document in this solution with the specified document ID.
/// </summary>
public AnalyzerConfigDocument? GetAnalyzerConfigDocument(DocumentId? documentId)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册