ClangFormat

ClangFormat 描述了一组基于 LibFormat 的工具。它可以通过各种方式支持您的工作流程,包括独立工具和编辑器集成。

独立工具

clang-format 位于 clang/tools/clang-format 中,可用于格式化 C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# 代码。

$ clang-format --help
OVERVIEW: A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code.

If no arguments are specified, it formats the code from standard input
and writes the result to the standard output.
If <file>s are given, it reformats the files. If -i is specified
together with <file>s, the files are edited in-place. Otherwise, the
result is written to the standard output.

USAGE: clang-format [options] [@<file>] [<file> ...]

OPTIONS:

Clang-format options:

  --Werror                       - If set, changes formatting warnings to errors
  --Wno-error=<value>            - If set don't error out on the specified warning type.
    =unknown                     -   If set, unknown format options are only warned about.
                                     This can be used to enable formatting, even if the
                                     configuration contains unknown (newer) options.
                                     Use with caution, as this might lead to dramatically
                                     differing format depending on an option being
                                     supported or not.
  --assume-filename=<string>     - Set filename used to determine the language and to find
                                   .clang-format file.
                                   Only used when reading from stdin.
                                   If this is not passed, the .clang-format file is searched
                                   relative to the current working directory when reading stdin.
                                   Unrecognized filenames are treated as C++.
                                   supported:
                                     CSharp: .cs
                                     Java: .java
                                     JavaScript: .mjs .js .ts
                                     Json: .json
                                     Objective-C: .m .mm
                                     Proto: .proto .protodevel
                                     TableGen: .td
                                     TextProto: .txtpb .textpb .pb.txt .textproto .asciipb
                                     Verilog: .sv .svh .v .vh
  --cursor=<uint>                - The position of the cursor when invoking
                                   clang-format from an editor integration
  --dry-run                      - If set, do not actually make the formatting changes
  --dump-config                  - Dump configuration options to stdout and exit.
                                   Can be used with -style option.
  --fail-on-incomplete-format    - If set, fail with exit code 1 on incomplete format.
  --fallback-style=<string>      - The name of the predefined style used as a
                                   fallback in case clang-format is invoked with
                                   -style=file, but can not find the .clang-format
                                   file to use. Defaults to 'LLVM'.
                                   Use -fallback-style=none to skip formatting.
  --ferror-limit=<uint>          - Set the maximum number of clang-format errors to emit
                                   before stopping (0 = no limit).
                                   Used only with --dry-run or -n
  --files=<filename>             - A file containing a list of files to process, one per line.
  -i                             - Inplace edit <file>s, if specified.
  --length=<uint>                - Format a range of this length (in bytes).
                                   Multiple ranges can be formatted by specifying
                                   several -offset and -length pairs.
                                   When only a single -offset is specified without
                                   -length, clang-format will format up to the end
                                   of the file.
                                   Can only be used with one input file.
  --lines=<string>               - <start line>:<end line> - format a range of
                                   lines (both 1-based).
                                   Multiple ranges can be formatted by specifying
                                   several -lines arguments.
                                   Can't be used with -offset and -length.
                                   Can only be used with one input file.
  -n                             - Alias for --dry-run
  --offset=<uint>                - Format a range starting at this byte offset.
                                   Multiple ranges can be formatted by specifying
                                   several -offset and -length pairs.
                                   Can only be used with one input file.
  --output-replacements-xml      - Output replacements as XML.
  --qualifier-alignment=<string> - If set, overrides the qualifier alignment style
                                   determined by the QualifierAlignment style flag
  --sort-includes                - If set, overrides the include sorting behavior
                                   determined by the SortIncludes style flag
  --style=<string>               - Set coding style. <string> can be:
                                   1. A preset: LLVM, GNU, Google, Chromium, Microsoft,
                                      Mozilla, WebKit.
                                   2. 'file' to load style configuration from a
                                      .clang-format file in one of the parent directories
                                      of the source file (for stdin, see --assume-filename).
                                      If no .clang-format file is found, falls back to
                                      --fallback-style.
                                      --style=file is the default.
                                   3. 'file:<format_file_path>' to explicitly specify
                                      the configuration file.
                                   4. "{key: value, ...}" to set specific parameters, e.g.:
                                      --style="{BasedOnStyle: llvm, IndentWidth: 8}"
  --verbose                      - If set, shows the list of processed files

Generic Options:

  --help                         - Display available options (--help-hidden for more)
  --help-list                    - Display list of available options (--help-list-hidden for more)
  --version                      - Display the version of this program

当所需的代码格式化样式与可用选项不同时,可以使用 -style="{key: value, ...}" 选项自定义样式,或者将您的样式配置放在项目目录中的 .clang-format_clang-format 文件中,并使用 clang-format -style=file

创建 .clang-format 文件的一种简单方法是

clang-format -style=llvm -dump-config > .clang-format

可用的样式选项在 Clang-Format 样式选项 中进行了描述。

.clang-format-ignore

您可以创建 .clang-format-ignore 文件,以使 clang-format 忽略某些文件。 .clang-format-ignore 文件包含文件路径名的模式。它具有以下格式

  • 空行将被跳过。

  • 每行的开头和结尾的空格将被修剪。

  • 以井号 (#) 开头的行是注释。

  • 非注释行是一个模式。

  • 斜杠 (/) 用作目录分隔符。

  • 模式相对于 .clang-format-ignore 文件的目录(如果模式以斜杠开头,则相对于根目录)。包含驱动器名的模式(例如 C:)不受支持。

  • 模式遵循 POSIX 2.13.1、2.13.2 和 2.13.3 的规则 1 中指定的规则。

  • 如果模式以感叹号 (!) 开头,则该模式会被否定。

要匹配目录中的所有文件,请使用例如 foo/bar/*。要匹配 .clang-format-ignore 文件目录中的所有文件,请使用 *。支持多个 .clang-format-ignore 文件,类似于 .clang-format 文件,较低级别的目录文件将覆盖较高级别的目录文件。

Vim 集成

有一个 vim 集成,允许您在当前缓冲区上运行 clang-format 独立工具,可以选择要重新格式化的区域。

此集成采用 python 文件的形式,可以在 clang/tools/clang-format/clang-format.py 中找到。

if has('python')
  map <C-K> :pyf <path-to-this-file>/clang-format.py<cr>
  imap <C-K> <c-o>:pyf <path-to-this-file>/clang-format.py<cr>
elseif has('python3')
  map <C-K> :py3f <path-to-this-file>/clang-format.py<cr>
  imap <C-K> <c-o>:py3f <path-to-this-file>/clang-format.py<cr>
endif

这可以通过在您的 .vimrc 中添加以下内容来集成

第一行在 NORMAL 和 VISUAL 模式下启用 clang-format,第二行添加了对 INSERT 模式的支持。如果您需要在不同的键上使用 clang-format,请将“C-K”更改为其他绑定(C-K 代表 Ctrl+k)。

使用此集成,您可以在绑定键上按下,clang-format 将在 NORMAL 和 INSERT 模式下格式化当前行,或者在 VISUAL 模式下格式化选定的区域。行或区域将扩展到下一个较大的语法实体。

它操作当前(可能是未保存的)缓冲区,并且不会创建或保存任何文件。要恢复格式,只需撤消。

function! Formatonsave()
  let l:formatdiff = 1
  pyf <path-to-this-file>/clang-format.py
endfunction
autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave()

另一种选择是在保存文件时格式化更改,从而将集成到编码工作流程中。为此,请将以下内容添加到您的 .vimrc

Emacs 集成

(load "<path-to-clang>/tools/clang-format/clang-format.el")
(global-set-key [C-M-tab] 'clang-format-region)

vim 的集成类似,还存在 emacs 的集成。它可以在 clang/tools/clang-format/clang-format.el 中找到,可以通过在您的 .emacs 中添加以下内容来使用

这将 clang-format-region 函数绑定到 C-M-tab,然后它将格式化当前行或选定的区域。

BBEdit 集成

clang-format 不能用作 BBEdit 的文本过滤器,但可以通过脚本很好地工作。用于执行此集成的 AppleScript 可以在 clang/tools/clang-format/clang-format-bbedit.applescript 中找到;将副本放在 ~/Library/Application Support/BBEdit/Scripts 中,并编辑其中的路径以指向您的 clang-format 的本地副本。

使用此集成,您可以从脚本菜单中选择脚本,clang-format 将格式化选择内容。请注意,您可以通过重命名脚本重命名菜单项,并可以在 BBEdit 首选项(在菜单和快捷方式下)中为菜单项分配键盘快捷键。

CLion 集成

clang-format 集成到 CLion 中,作为一种可选的代码格式化程序。当项目根目录下存在 .clang-format 文件时,CLion 会自动启用它。代码样式规则在您键入时应用,包括缩进、自动完成、代码生成和重构。

clang-format 也可以在没有 .clang-format 文件的情况下启用。在这种情况下,CLion 会提示您根据当前 IDE 设置或默认 LLVM 样式创建一个。

Visual Studio 集成

alpha 构建站点 下载最新的 Visual Studio 扩展。默认的按键绑定是 Ctrl-R,Ctrl-F。

Visual Studio Code 集成

Visual Studio Marketplace 获取最新的 Visual Studio Code 扩展。默认的按键绑定是 Alt-Shift-F。

Git 集成

% git clang-format -h
usage: git clang-format [OPTIONS] [<commit>] [<commit>|--staged] [--] [<file>...]

If zero or one commits are given, run clang-format on all lines that differ
between the working directory and <commit>, which defaults to HEAD.  Changes are
only applied to the working directory, or in the stage/index.

Examples:
  To format staged changes, i.e everything that's been `git add`ed:
    git clang-format

  To also format everything touched in the most recent commit:
    git clang-format HEAD~1

  If you're on a branch off main, to format everything touched on your branch:
    git clang-format main

If two commits are given (requires --diff), run clang-format on all lines in the
second <commit> that differ from the first <commit>.

The following git-config settings set the default of the corresponding option:
  clangFormat.binary
  clangFormat.commit
  clangFormat.extensions
  clangFormat.style

positional arguments:
  <commit>              revision from which to compute the diff
  <file>...             if specified, only consider differences in these files

optional arguments:
  -h, --help            show this help message and exit
  --binary BINARY       path to clang-format
  --commit COMMIT       default commit to use if none is specified
  --diff                print a diff instead of applying the changes
  --diffstat            print a diffstat instead of applying the changes
  --extensions EXTENSIONS
                        comma-separated list of file extensions to format, excluding the period and case-insensitive
  -f, --force           allow changes to unstaged files
  -p, --patch           select hunks interactively
  -q, --quiet           print less information
  --staged, --cached    format lines in the stage instead of the working dir
  --style STYLE         passed to clang-format
  -v, --verbose         print extra information

脚本 clang/tools/clang-format/git-clang-format 可用于格式化 git 提交中修改的代码行

用于补丁重新格式化的脚本

usage: clang-format-diff.py [-h] [-i] [-p NUM] [-regex PATTERN] [-iregex PATTERN] [-sort-includes] [-v] [-style STYLE]
                            [-fallback-style FALLBACK_STYLE] [-binary BINARY]

This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users:

  git diff -U0 --no-color --relative HEAD^ | clang-format-diff.py -p1 -i
  svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i

It should be noted that the filename contained in the diff is used unmodified
to determine the source file to update. Users calling this script directly
should be careful to ensure that the path in the diff is correct relative to the
current working directory.

optional arguments:
  -h, --help            show this help message and exit
  -i                    apply edits to files instead of displaying a diff
  -p NUM                strip the smallest prefix containing P slashes
  -regex PATTERN        custom pattern selecting file paths to reformat (case sensitive, overrides -iregex)
  -iregex PATTERN       custom pattern selecting file paths to reformat (case insensitive, overridden by -regex)
  -sort-includes        let clang-format sort include blocks
  -v, --verbose         be more verbose, ineffective without -i
  -style STYLE          formatting style to apply (LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit)
  -fallback-style FALLBACK_STYLE
                        The name of the predefined style used as a fallback in case clang-format is invoked with-style=file, but can not
                        find the .clang-formatfile to use.
  -binary BINARY        location of binary to use for clang-format

python 脚本 clang/tools/clang-format/clang-format-diff.py 解析统一差异的输出,并使用 clang-format 重新格式化所有包含的代码行。

hg diff -U0 --color=never | clang-format-diff.py -i -p1

要重新格式化最新 Mercurial/hg 提交中的所有代码行,请执行以下操作

选项 -U0 将创建一个没有上下文行的差异(脚本也会格式化这些上下文行)。