Roslyn将允许我将文件添加到AdhocWorkspace并在其上运行格式化程序,但是我看不到如何指定格式化选项。我想从命令行中传递的.editorconfig
文件中获取它们
var adhoc = new AdhocWorkspace();
var solutionInfo = SolutionInfo.Create(SolutionId.CreateNewId(),
VersionStamp.Default,
"MySolution");
adhoc.AddSolution(solutionInfo);
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(),
VersionStamp.Default,
"MyProject",
"MyProject.dll",
Microsoft.CodeAnalysis.LanguageNames.CSharp);
adhoc.AddProject(projectInfo);
foreach(var arg in args) {
var sourceText = SourceText.From(File.OpenText(arg).BaseStream);
adhoc.AddDocument(projectInfo.Id, arg, sourceText);
}
foreach(var document in adhoc.CurrentSolution.Projects.First().Documents){
var formattedDocument = Formatter.FormatAsync(document, adhoc.Options).Result;
var formattedText = formattedDocument.GetTextAsync().Result;
Console.WriteLine(formattedText);
}
adhoc.Options = adhoc.Options.WithChangedOption(...)
将允许我更改单个选项,但我希望这些选项来自.editorconfig
文件。是否有API可以让我做到这一点?
答案 0 :(得分:2)
我找到了这个项目:https://github.com/dotnet/format
我了解了它的工作原理,并简化了解析.editorconfig的过程:
public static OptionSet SimplifiedParsing(Workspace space)
{
OptionSet optionsSet = space.Options;
//reading .editorconfig
var editorConfigDictionary = File.ReadAllLines(@".editorconfig")
//here I take only the ones for csharp
.Where(x => x.StartsWith("csharp"))
.Select(x => x.Split(" = "))
.ToDictionary(x => x[0], y => y[1]);
var commonOptionsType = typeof(FormattingOptions);
var csharpOptionsType = typeof(CSharpFormattingOptions);
var formattingTypes = new[] {commonOptionsType, csharpOptionsType};
var optionType = typeof(IOption);
//here we are filtering all the methods from formattingTypes classes, with reflection, which parse the options by keys which are in editor config
var allParsingMethods = formattingTypes
.SelectMany(t => t.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty))
.Where(p => optionType.IsAssignableFrom(p.PropertyType))
.Select(p => (IOption) p.GetValue(null))
.Select(GetParsingMethod)
.Where(ows => ows.Item2 != null)
.ToImmutableArray();
foreach ((IOption, OptionStorageLocation, MethodInfo) parsingMethod in allParsingMethods)
{
//taking info for invoking TryGetOption
var (option, editorConfigStorage, tryGetOptionMethod) = parsingMethod;
object result = null;
//arguments for reflection invocation
var args = new[] {editorConfigDictionary, option.Type, result};
//editorConfigStorage instance on which to call the method
//invoking bool TryGetOption(IReadOnlyDictionary<string, string> rawOptions, Type type, out object result)
var isOptionPresent = (bool) tryGetOptionMethod.Invoke(editorConfigStorage, args);
result = args[2];
if (isOptionPresent)
{
var optionKey = new OptionKey(option, option.IsPerLanguage ? LanguageNames.CSharp : null);
//if option is parsed -> its present and we can add it to OptionSet
optionsSet = optionsSet.WithChangedOption(optionKey, result);
}
}
return optionsSet;
//helpers
(IOption, OptionStorageLocation, MethodInfo) GetParsingMethod(IOption option)
{
var editorConfigStorage = option.StorageLocations.IsDefaultOrEmpty
? null
: option.StorageLocations.FirstOrDefault(IsEditorConfigStorage);
//getting TryGetOption method of EditorConfigStorageLocation<T>
// original method signature:
// public bool TryGetOption(IReadOnlyDictionary<string, string> rawOptions, Type type, out object result)
var tryGetOptionMethod = editorConfigStorage?.GetType().GetMethod("TryGetOption");
return (option, editorConfigStorage, tryGetOptionMethod);
}
bool IsEditorConfigStorage(OptionStorageLocation storageLocation)
{
return storageLocation.GetType().FullName
.StartsWith("Microsoft.CodeAnalysis.Options.EditorConfigStorageLocation");
}
}