【问题标题】:Is there a way to enforce using tabs instead of spaces?有没有办法强制使用制表符而不是空格?
【发布时间】:2011-01-17 20:51:48
【问题描述】:

StyleCop 提供检查空格使用的一致性,但遗憾的是缺少相反的想法:强制源代码使用制表符。有没有办法添加这个功能?它不一定是 StyleCop,也欢迎使用其他工具。

【问题讨论】:

  • 这是慢慢强迫某人用理智的缩进编写代码的一步。看着他们当前的代码让我头晕目眩。
  • 祝你好运!我的祈祷与你同在。
  • 我当然希望这是默认设置。即使不是,包含这条规则也是一件好事。
  • @JeffCyr 我不关心代码的剪切和粘贴友好性(至少,与 Visual Studio 之外的任何源之间)。我关心的是讨厌的开发人员在用空格排列代码的开销,以及如何必须按退格键 4 次才能返回一个缩进级别。选项卡还允许不同的团队成员使用不同的文字空间(例如,我可以看到选项卡占用 3 个空间,而其他人使用 4 个)。
  • 我和 ErikE 在一起。管理和导航空间是一件令人头疼的事情。我唯一遇到剪切和粘贴问题的是使用电子邮件时。偶尔解决这个问题比忍受烦人的 IDE 体验要容易得多。

标签: c# indentation stylecop


【解决方案1】:

我也是一个不使用制表符的人,尽管有很多理由使用其中一个,并且还有其他地方可以了解为什么你认为一个比另一个更好. :)

我实际上想要同样的东西——检查制表符缩进的规则——所以我根据 StyleCop 的 SpacingRules 源代码编写了它。它似乎工作得相当好,尽管到目前为止我只在几个项目中使用过它。它可能会被优化或其他什么......但它可以工作。

using System;
using System.Text.RegularExpressions;
using Microsoft.StyleCop;
using Microsoft.StyleCop.CSharp;

namespace CustomRules.StyleCop.CSharp
{
  [SourceAnalyzer(typeof(CsParser))]
  public class SpacingRules : SourceAnalyzer
  {
    public SpacingRules()
    {
    }

    public override void AnalyzeDocument(CodeDocument document)
    {
      Param.RequireNotNull(document, "document");

      CsDocument csdocument = (CsDocument)document;
      if (csdocument.RootElement != null && !csdocument.RootElement.Generated)
      {
        this.CheckSpacing(csdocument.Tokens);
      }
    }

    private void CheckSpacing(MasterList<CsToken> tokens)
    {
      Param.AssertNotNull(tokens, "tokens");

      foreach (var token in tokens)
      {
        if (this.Cancel)
        {
          break;
        }

        if (token.Generated)
        {
          continue;
        }

        switch (token.CsTokenType)
        {
          case CsTokenType.WhiteSpace:
            this.CheckWhitespace(token as Whitespace);
            break;

          case CsTokenType.XmlHeader:
            XmlHeader header = (XmlHeader)token;
            foreach (var xmlChild in header.ChildTokens)
            {
              this.CheckTabsInComment(xmlChild);
            }
            break;

          case CsTokenType.SingleLineComment:
          case CsTokenType.MultiLineComment:
            this.CheckTabsInComment(token);
            break;
        }

        switch (token.CsTokenClass)
        {
          case CsTokenClass.ConstructorConstraint:
            this.CheckSpacing(((ConstructorConstraint)token).ChildTokens);
            break;

          case CsTokenClass.GenericType:
            this.CheckGenericSpacing((GenericType)token);
            this.CheckSpacing(((TypeToken)token).ChildTokens);
            break;

          case CsTokenClass.Type:
            this.CheckSpacing(((TypeToken)token).ChildTokens);
            break;
        }
      }
    }

    private void CheckGenericSpacing(GenericType generic)
    {
      Param.AssertNotNull(generic, "generic");
      if (generic.ChildTokens.Count == 0)
      {
        return;
      }

      foreach (var token in generic.ChildTokens)
      {
        if (this.Cancel)
        {
          break;
        }

        if (token.CsTokenClass == CsTokenClass.GenericType)
        {
          this.CheckGenericSpacing(token as GenericType);
        }

        if (!token.Generated && token.CsTokenType == CsTokenType.WhiteSpace)
        {
          this.CheckWhitespace(token as Whitespace);
        }
      }
    }

    private void CheckWhitespace(Whitespace whitespace)
    {
      Param.AssertNotNull(whitespace, "whitespace");

      if (whitespace.Location.StartPoint.IndexOnLine == 0 && Regex.IsMatch(whitespace.Text, "^ +"))
      {
        this.AddViolation(whitespace.FindParentElement(), whitespace.LineNumber, "TabsMustBeUsed");
      }
    }

    private void CheckTabsInComment(CsToken comment)
    {
      Param.AssertNotNull(comment, "comment");

      var lines = comment.Text.Split('\n');
      for (int i = 0; i < lines.Length; i++)
      {
        if (Regex.IsMatch(lines[i], "^ +"))
        {
          this.AddViolation(comment.FindParentElement(), comment.LineNumber + i, "TabsMustBeUsed");
        }
      }
    }
  }
}

请注意,您还必须在程序集中将嵌入的 XML 文件“SpacingRules.xml”与这个东西放在一起。 (阅读 StyleCop SDK 文档了解更多信息。)

<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="Custom Spacing Rules">
  <Description>
    Rules which verify the spacing placed between keywords and symbols in the code.
  </Description>
  <Rules>
    <Rule Name="TabsMustBeUsed" CheckId="MY1027">
      <Context>Spaces are not allowed. Use tabs instead.</Context>
      <Description>Verifies that the code does not contain spaces.</Description>
    </Rule>
  </Rules>
</SourceAnalyzer>

【讨论】:

    【解决方案2】:

    您可以使用StyleCop+ 插件来强制使用选项卡。

    下载 StyleCopPlus.dll 后,将其放在 StyleCop 主文件夹 C:\Program Files (x86)\StyleCop 4.7\Custom Rules 内的 Custom Rules 文件夹中,或直接放在主文件夹中。

    现在,当使用StyleCopSettingsEditor 打开Settings.StyleCop 时,您将能够设置规则SP2001: CheckAllowedIndentationCharacters

    可以在StyleCop+ 标签下、More Custom Rules 子标签下、Formatting 标题下找到此规则:

    【讨论】:

    • 我还没有尝试过,但从描述中看起来很棒,谢谢!
    • @mafutrct:欢迎您 :) 我对其进行了测试并且可以正常工作。在制表符和空格之间拥有这种灵活性真是太好了。
    【解决方案3】:

    假设您使用 Visual Studio 作为您的 IDE,并且您的团队成员认同这个想法,您可以做的一件事是将 VS 设置为使用制表符而不是空格,导出并共享设置文件.

    该设置可以在工具 > 选项 > 文本编辑器 > 所有语言(或您希望使用的语言)> 选项卡下找到,然后在右侧您可以选择“插入空格”或“保留选项卡”。

    要从 Visual Studio 中导出设置:工具 > 导入和导出设置 > 导出选定的环境设置 > 选择“选项”

    只是一个想法 - 但老实说,真正的问题似乎是你队友的支持。否则,他们总是可以恢复到他们的设置。或者,在登记入住时,正如 Sam 建议的那样,您可以进行一些自动重新格式化。

    HTH

    【讨论】:

      【解决方案4】:

      打包方式:

      目前的趋势似乎是通过 nuget 包来做到这一点(并且经典的 StyleCop 可能会在某个时候逐步淘汰)。因此,要对包执行此操作,请执行以下操作:

      通过 nuget:

      Install-Package Microsoft.CodeAnalysis.FxCopAnalyzers
      Install-Package StyleCop.Analyzers -Version 1.1.0-beta006
      

      注意对预发布的引用(此时),选项卡的设置仅在测试版中可用。

      将以下代码作为 ca.ruleset 添加到您的项目中:

      <?xml version="1.0" encoding="utf-8"?>
      <RuleSet Name="Custom Rulset" Description="Custom Rulset" ToolsVersion="14.0">
          <Rules AnalyzerId="AsyncUsageAnalyzers" RuleNamespace="AsyncUsageAnalyzers">
              <Rule Id="UseConfigureAwait" Action="Warning" />
          </Rules>
          <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
              <Rule Id="CA1001" Action="Warning" />
              <Rule Id="CA1009" Action="Warning" />
              <Rule Id="CA1016" Action="Warning" />
              <Rule Id="CA1033" Action="Warning" />
              <Rule Id="CA1049" Action="Warning" />
              <Rule Id="CA1060" Action="Warning" />
              <Rule Id="CA1061" Action="Warning" />
              <Rule Id="CA1063" Action="Warning" />
              <Rule Id="CA1065" Action="Warning" />
              <Rule Id="CA1301" Action="Warning" />
              <Rule Id="CA1400" Action="Warning" />
              <Rule Id="CA1401" Action="Warning" />
              <Rule Id="CA1403" Action="Warning" />
              <Rule Id="CA1404" Action="Warning" />
              <Rule Id="CA1405" Action="Warning" />
              <Rule Id="CA1410" Action="Warning" />
              <Rule Id="CA1415" Action="Warning" />
              <Rule Id="CA1821" Action="Warning" />
              <Rule Id="CA1900" Action="Warning" />
              <Rule Id="CA1901" Action="Warning" />
              <Rule Id="CA2002" Action="Warning" />
              <Rule Id="CA2100" Action="Warning" />
              <Rule Id="CA2101" Action="Warning" />
              <Rule Id="CA2108" Action="Warning" />
              <Rule Id="CA2111" Action="Warning" />
              <Rule Id="CA2112" Action="Warning" />
              <Rule Id="CA2114" Action="Warning" />
              <Rule Id="CA2116" Action="Warning" />
              <Rule Id="CA2117" Action="Warning" />
              <Rule Id="CA2122" Action="Warning" />
              <Rule Id="CA2123" Action="Warning" />
              <Rule Id="CA2124" Action="Warning" />
              <Rule Id="CA2126" Action="Warning" />
              <Rule Id="CA2131" Action="Warning" />
              <Rule Id="CA2132" Action="Warning" />
              <Rule Id="CA2133" Action="Warning" />
              <Rule Id="CA2134" Action="Warning" />
              <Rule Id="CA2137" Action="Warning" />
              <Rule Id="CA2138" Action="Warning" />
              <Rule Id="CA2140" Action="Warning" />
              <Rule Id="CA2141" Action="Warning" />
              <Rule Id="CA2146" Action="Warning" />
              <Rule Id="CA2147" Action="Warning" />
              <Rule Id="CA2149" Action="Warning" />
              <Rule Id="CA2200" Action="Warning" />
              <Rule Id="CA2202" Action="Warning" />
              <Rule Id="CA2207" Action="Warning" />
              <Rule Id="CA2212" Action="Warning" />
              <Rule Id="CA2213" Action="Warning" />
              <Rule Id="CA2214" Action="Warning" />
              <Rule Id="CA2216" Action="Warning" />
              <Rule Id="CA2220" Action="Warning" />
              <Rule Id="CA2229" Action="Warning" />
              <Rule Id="CA2231" Action="Warning" />
              <Rule Id="CA2232" Action="Warning" />
              <Rule Id="CA2235" Action="Warning" />
              <Rule Id="CA2236" Action="Warning" />
              <Rule Id="CA2237" Action="Warning" />
              <Rule Id="CA2238" Action="Warning" />
              <Rule Id="CA2240" Action="Warning" />
              <Rule Id="CA2241" Action="Warning" />
              <Rule Id="CA2242" Action="Warning" />
              <Rule Id="CA1012" Action="Warning" />
          </Rules>
          <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
              <Rule Id="SA1305" Action="Warning" />
              <Rule Id="SA1412" Action="Warning" />
              <Rule Id="SA1600" Action="None" />
              <Rule Id="SA1609" Action="Warning" />
          </Rules>
      </RuleSet>
      

      通过编辑 .csproj 文件并将其添加到您的项目文件并添加:

      <PropertyGroup>
          <CodeAnalysisRuleSet>ca.ruleset</CodeAnalysisRuleSet>
      </PropertyGroup>
      

      要覆盖选项卡(和其他)设置,您需要将 stylecop.json 文件添加到您的项目中。在文件属性中,将构建操作设置为“(分析器)附加文件”。根据项目类型,实际的“分析器”一词可能不存在。

      将 stylecop.json 文件编辑为如下内容:

      {
        "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
        "settings": {
          "documentationRules": {
            "companyName": "YourCompanyName",
            "copyrightText": "Copyright (c) {companyName}. All Rights Reserved.\r\nLicensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.",
            "xmlHeader": false,
            "fileNamingConvention": "metadata"
          },
          "indentation": {
            "useTabs": true
          }
        }
      }
      

      至少对于 .NET 标准项目,您需要确保 csproj 文件中包含以下内容(并且没有其他对文件的引用):

      <ItemGroup>
        <AdditionalFiles Include="stylecop.json" />
      </ItemGroup>
      

      您可能需要重新加载项目和包才能让它们识别 stylecop.json 文件。

      参考资料:

      DotNetAnalyzers/StyleCopAnalyzers

      .NET Core, Code Analysis and StyleCop

      【讨论】:

        【解决方案5】:

        StyleCop 支持创建自定义规则,因此您可以添加自己的“使用前导制表符代替空格”规则。如果您不想尝试自己开发,可以通过http://stylecopcontrib.codeplex.com/http://github.com/AArnott/nerdbank.stylecop.rules 获取现有规则。

        【讨论】:

          【解决方案6】:

          好的,我设法找出了问题,因为出现此警告的原因,似乎是因为开发人员有时会复制并粘贴代码

          如果你使用的是 VS2010 转到解决方案资源管理器 检查设置风格警察 然后修改样式 Cop 中的设置,例如禁用或取消选中设置[Spacing.....]

          【讨论】:

            【解决方案7】:

            在您的源代码控制服务器中执行此操作。使用预提交脚本检查文件中是否有以多个空格开头的行并阻止提交。

            我同意制表符比空格更好。这是个人喜好,但团队的一致性非常重要。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-12-17
              • 2013-09-29
              • 2010-12-01
              • 2016-04-21
              • 1970-01-01
              • 2017-10-07
              相关资源
              最近更新 更多