自动格式化命令行中的代码

24

是否可以在解决方案中运行自动格式化代码,例如在Visual Studio中使用(Ctrl+K,Ctrl+D)格式化,但是通过命令行操作? 或者从命令行使用Resharper的cleanup来清理解决方案文件?


2
你尝试过什么吗?能给我们展示一下吗? - Hanlet Escaño
我认为(此时不在计算机旁无法测试),Ctrl + K,Ctrl + D并不是ReSharper独有的,所以也许你问题中的标签是不必要的! - JMK
这个回答说Resharper API没有用: https://dev59.com/iGvXa4cB1Zd3GeqPL7ic?rq=1 这个建议 http://www.narrange.net/doc/index.htm 提供了第三方控制台工具。 有趣的是,新版本的VS2012中是否添加了这样的新功能来支持命令行? - Александр Киричек
我已经编辑了你的标题。请查看“问题的标题应该包含‘标签’吗?”,在那里达成的共识是“不应该”。 - John Saunders
谢谢你,约翰。 JMK,Ctrl+K,Ctrl+D是用于IDE的。对于Resharper专属的是清理。 - Александр Киричек
5个回答

12
创建自己的工具。您可以使用EnvDTEEnvDTE80来创建Visual Studio项目,并即时加载要格式化的文件。完成后删除Visual Studio项目。您可以指定在格式化时不显示Visual Studio窗口。如果您感兴趣,请告诉我,我可以给您一些代码来使其工作。
更新: 我复制了我拥有的代码。我用它来格式化*.js文件。我删掉了一些您不需要的代码。如果它不能正常工作,请随时问我。
    //You need to make a reference to two dlls:
    envdte
    envdte80



    void FormatFiles(List<FileInfo> files)
    {       
        //If it throws exeption you may want to retry couple more times
        EnvDTE.Solution soln = System.Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.Solution.11.0")) as EnvDTE.Solution;
        //try this if you have Visual Studio 2010
        //EnvDTE.Solution soln = System.Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.Solution.10.0")) as EnvDTE.Solution;
        soln.DTE.MainWindow.Visible = false;
        EnvDTE80.Solution2 soln2 = soln as EnvDTE80.Solution2;
        //Creating Visual Studio project
        string csTemplatePath = soln2.GetProjectTemplate("ConsoleApplication.zip", "CSharp");
        soln.AddFromTemplate(csTemplatePath, tempPath, "FormattingFiles", false);
        //If it throws exeption you may want to retry couple more times
        Project project = soln.Projects.Item(1);

        foreach (FileInfo file in files)
        {
            ProjectItem addedItem;
            bool existingFile = false;
            int _try = 0;
            while (true)
            {            
                try
                {
                    string fileName = file.Name;
                    _try++;
                    if (existingFile)
                    {
                        fileName = file.Name.Substring(0, (file.Name.Length - file.Extension.Length) - 1);
                        fileName = fileName + "_" + _try + file.Extension;
                    }
                    addedItem = project.ProjectItems.AddFromTemplate(file.FullName, fileName);
                    existingFile = false;
                    break;
                }
                catch(Exception ex)
                {
                    if (ex.Message.Contains(file.Name) && ex.Message.Contains("already a linked file"))
                    {
                        existingFile = true;
                    }
                }
            }
            while (true)
            {
                //sometimes formatting file might throw an exception. Thats why I am using loop.
                //usually first time will work
                try
                {
                    addedItem.Open(Constants.vsViewKindCode);
                    addedItem.Document.Activate();
                    addedItem.Document.DTE.ExecuteCommand("Edit.FormatDocument");
                    addedItem.SaveAs(file.FullName);
                    break;
                }
                catch
                {
                    //repeat
                }
            }
        }
        try
        {
            soln.Close();
            soln2.Close();
            soln = null;
            soln2 = null;
        }
        catch
        {
            //for some reason throws exception. Not all the times.
            //if this doesn't closes the solution CleanUp() will take care of this thing
        }
        finally
        {
            CleanUp();
        }
    }   

    void CleanUp()
    {
        List<System.Diagnostics.Process> visualStudioProcesses = System.Diagnostics.Process.GetProcesses().Where(p => p.ProcessName.Contains("devenv")).ToList();
        foreach (System.Diagnostics.Process process in visualStudioProcesses)
        {
            if (process.MainWindowTitle == "")
            {
                process.Kill();
                break;
            }
        }
        tempPath = System.IO.Path.GetTempPath();
        tempPath = tempPath + "\\FormattingFiles";
        new DirectoryInfo(tempPath).Delete(true);
    } 

我希望这可以帮到你。

COM异常可以通过正确实现消息过滤来轻松解决,具体方法请参见此处 - Michal Hosala

5
作为Dilshod帖子的后续,如果你只是想格式化单个文件,这里有一种不需要临时路径的方法:
static void FormatFile(string file)
{
    EnvDTE.Solution soln = System.Activator.CreateInstance(
        Type.GetTypeFromProgID("VisualStudio.Solution.10.0")) as EnvDTE.Solution;

    soln.DTE.ItemOperations.OpenFile(file);

    TextSelection selection = soln.DTE.ActiveDocument.Selection as TextSelection;
    selection.SelectAll();
    selection.SmartFormat();

    soln.DTE.ActiveDocument.Save();
}

请注意,“file”很可能需要在磁盘上具有完整路径。相对路径似乎不起作用(虽然我没有尝试得很努力)。

此外,为了完整性,您可能需要实现此COM侦听器以捕获一些随机繁忙错误,您可以在此处获取:http://msdn.microsoft.com/en-us/library/ms228772.aspx - Jay Lemmon
这个解决方案对我来说不起作用。在尝试使用SmartFormat时会抛出错误。我还实现了MessageFilter - Patrick Magee
你使用的是哪个版本的Visual Studio?你需要确保你的“VisualStudio.Solution.10.0”与你的版本相匹配。例如:对于VS2013,它应该是“VisualStudio.Solution.12.0”。如果这样做不起作用,你可以查看我当前在http://svn.darwinbots.com/Darwinbots3/Trunk/Modules/Reformatter/Program.cs上正在做什么,并查看是否有我没有提到的东西。在我的机器上工作 :) - Jay Lemmon
嗨Jay,谢谢你的回复。我最终使用了Tools.CommandWindow并使用了document.Activate();接着是CommandWindow.SendInput("Edit.FormatDocument") - Patrick Magee
@PatrickMagee,您能否发布您的完整解决方案?我遇到了同样的问题,不知道该如何解决。谢谢! - user1935724

5

若要格式化.NET Core C#源代码,请使用 https://github.com/dotnet/format

按照项目的自述文件安装工具。

我需要对从Razor模板生成的一些代码文件进行格式化。我在输出文件夹的根目录下创建了一个外壳.CSProj文件,使用dotnet new console命令可以得到以下基本文件:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <RootNamespace>dotnet_format</RootNamespace>
  </PropertyGroup>

</Project>

然后在该文件夹中的 VS 命令提示符中运行 dotnet format 命令。它会递归地进入子目录并格式化找到的所有内容。要格式化特定的文件,可以使用 --files 开关并提供文件名列表。


2
使用.NET团队的CodeFormatter
  1. 安装MSBuild Tools 2015
  2. 下载CodeFormatter 1.0.0-alpha6
  3. CodeFormatter.csproj添加到您的项目的根目录中:

CodeFormatter.csproj

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Compile Include="**\*.cs" />
  </ItemGroup>
  <Target Name="Compile">
    <Csc Sources="@(Compile)"/>
  </Target>
</Project>

然后从命令行运行此命令。
> codeformatter.exe CodeFormatter.csproj /nocopyright

结果:您所有项目的 C# 文件现在遵循大多数 .NET Foundation 编码准则。
备注:
  • 安装 MSBuild Tools 2015 意味着我们不需要 Visual Studio。
  • CodeFormatter.csproj 添加到根目录会递归包含所有 C# 文件,这意味着上述内容适用于基于 project.json 和 *.xproj 的设置。
另请参阅。

http://bigfontblog.azurewebsites.net/autoformat/


1

太好了,谢谢,这确实是一个解决方案。 但是,这个项目在Source Forge上的最后更新日期是2011年11月21日。 NArrange最后更新日期:2011年5月25日。 也许有新的东西存在。 - Александр Киричек

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接