aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/fmt/support
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-11-07 14:49:13 +0100
committerGitHub Enterprise <[email protected]>2025-11-07 14:49:13 +0100
commit24e43a913f29ac3b314354e8ce5175f135bcc64f (patch)
treeca442937ceeb63461012b33a4576e9835099f106 /thirdparty/fmt/support
parentget oplog attachments (#622) (diff)
downloadzen-24e43a913f29ac3b314354e8ce5175f135bcc64f.tar.xz
zen-24e43a913f29ac3b314354e8ce5175f135bcc64f.zip
switch to xmake for package management (#611)
This change removes our dependency on vcpkg for package management, in favour of bringing some code in-tree in the `thirdparty` folder as well as using the xmake build-in package management feature. For the latter, all the package definitions are maintained in the zen repo itself, in the `repo` folder. It should now also be easier to build the project as it will no longer depend on having the right version of vcpkg installed, which has been a common problem for new people coming in to the codebase. Now you should only need xmake to build. * Bumps xmake requirement on github runners to 2.9.9 to resolve an issue where xmake on Windows invokes cmake with `v144` toolchain which does not exist * BLAKE3 is now in-tree at `thirdparty/blake3` * cpr is now in-tree at `thirdparty/cpr` * cxxopts is now in-tree at `thirdparty/cxxopts` * fmt is now in-tree at `thirdparty/fmt` * robin-map is now in-tree at `thirdparty/robin-map` * ryml is now in-tree at `thirdparty/ryml` * sol2 is now in-tree at `thirdparty/sol2` * spdlog is now in-tree at `thirdparty/spdlog` * utfcpp is now in-tree at `thirdparty/utfcpp` * xmake package repo definitions is in `repo` * implemented support for sanitizers. ASAN is supported on windows, TSAN, UBSAN, MSAN etc are supported on Linux/MacOS though I have not yet tested it extensively on MacOS * the zencore encryption implementation also now supports using mbedTLS which is used on MacOS, though for now we still use openssl on Linux * crashpad * bumps libcurl to 8.11.0 (from 8.8.0) which should address a rare build upload bug
Diffstat (limited to 'thirdparty/fmt/support')
-rw-r--r--thirdparty/fmt/support/Android.mk15
-rw-r--r--thirdparty/fmt/support/AndroidManifest.xml1
-rw-r--r--thirdparty/fmt/support/C++.sublime-syntax2061
-rw-r--r--thirdparty/fmt/support/README4
-rw-r--r--thirdparty/fmt/support/Vagrantfile19
-rw-r--r--thirdparty/fmt/support/build.gradle132
-rwxr-xr-xthirdparty/fmt/support/check-commits43
-rw-r--r--thirdparty/fmt/support/cmake/FindSetEnv.cmake7
-rw-r--r--thirdparty/fmt/support/cmake/JoinPaths.cmake26
-rw-r--r--thirdparty/fmt/support/cmake/fmt-config.cmake.in7
-rw-r--r--thirdparty/fmt/support/cmake/fmt.pc.in11
-rw-r--r--thirdparty/fmt/support/docopt.py581
-rwxr-xr-xthirdparty/fmt/support/mkdocs78
-rw-r--r--thirdparty/fmt/support/mkdocs.yml48
-rwxr-xr-xthirdparty/fmt/support/printable.py201
-rw-r--r--thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/__init__.py338
-rw-r--r--thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/templates/README1
-rwxr-xr-xthirdparty/fmt/support/release.py188
18 files changed, 3761 insertions, 0 deletions
diff --git a/thirdparty/fmt/support/Android.mk b/thirdparty/fmt/support/Android.mk
new file mode 100644
index 000000000..84a3e32f0
--- /dev/null
+++ b/thirdparty/fmt/support/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fmt_static
+LOCAL_MODULE_FILENAME := libfmt
+
+LOCAL_SRC_FILES := ../src/format.cc
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS += -std=c++11 -fexceptions
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/thirdparty/fmt/support/AndroidManifest.xml b/thirdparty/fmt/support/AndroidManifest.xml
new file mode 100644
index 000000000..c282ef5a5
--- /dev/null
+++ b/thirdparty/fmt/support/AndroidManifest.xml
@@ -0,0 +1 @@
+<manifest package="dev.fmt" />
diff --git a/thirdparty/fmt/support/C++.sublime-syntax b/thirdparty/fmt/support/C++.sublime-syntax
new file mode 100644
index 000000000..9dfb5cbe4
--- /dev/null
+++ b/thirdparty/fmt/support/C++.sublime-syntax
@@ -0,0 +1,2061 @@
+%YAML 1.2
+---
+# http://www.sublimetext.com/docs/3/syntax.html
+name: C++ (fmt)
+comment: I don't think anyone uses .hp. .cp tends to be paired with .h. (I could be wrong. :) -- chris
+file_extensions:
+ - cpp
+ - cc
+ - cp
+ - cxx
+ - c++
+ - C
+ - h
+ - hh
+ - hpp
+ - hxx
+ - h++
+ - inl
+ - ipp
+first_line_match: '-\*- C\+\+ -\*-'
+scope: source.c++
+variables:
+ identifier: \b[[:alpha:]_][[:alnum:]_]*\b # upper and lowercase
+ macro_identifier: \b[[:upper:]_][[:upper:][:digit:]_]{2,}\b # only uppercase, at least 3 chars
+ path_lookahead: '(?:::\s*)?(?:{{identifier}}\s*::\s*)*(?:template\s+)?{{identifier}}'
+ operator_method_name: '\boperator\s*(?:[-+*/%^&|~!=<>]|[-+*/%^&|=!<>]=|<<=?|>>=?|&&|\|\||\+\+|--|,|->\*?|\(\)|\[\]|""\s*{{identifier}})'
+ casts: 'const_cast|dynamic_cast|reinterpret_cast|static_cast'
+ operator_keywords: 'and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|xor|xor_eq|noexcept'
+ control_keywords: 'break|case|catch|continue|default|do|else|for|goto|if|_Pragma|return|switch|throw|try|while'
+ memory_operators: 'new|delete'
+ basic_types: 'asm|__asm__|auto|bool|_Bool|char|_Complex|double|float|_Imaginary|int|long|short|signed|unsigned|void'
+ before_tag: 'struct|union|enum\s+class|enum\s+struct|enum|class'
+ declspec: '__declspec\(\s*\w+(?:\([^)]+\))?\s*\)'
+ storage_classes: 'static|export|extern|friend|explicit|virtual|register|thread_local'
+ type_qualifier: 'const|constexpr|mutable|typename|volatile'
+ compiler_directive: 'inline|restrict|__restrict__|__restrict'
+ visibility_modifiers: 'private|protected|public'
+ other_keywords: 'typedef|nullptr|{{visibility_modifiers}}|static_assert|sizeof|using|typeid|alignof|alignas|namespace|template'
+ modifiers: '{{storage_classes}}|{{type_qualifier}}|{{compiler_directive}}'
+ non_angle_brackets: '(?=<<|<=)'
+
+ regular: '[^(){}&;*^%=<>-]*'
+ paren_open: (?:\(
+ paren_close: '\))?'
+ generic_open: (?:<
+ generic_close: '>)?'
+ balance_parentheses: '{{regular}}{{paren_open}}{{regular}}{{paren_close}}{{regular}}'
+ generic_lookahead: <{{regular}}{{generic_open}}{{regular}}{{generic_open}}{{regular}}{{generic_close}}\s*{{generic_close}}{{balance_parentheses}}>
+
+ data_structures_forward_decl_lookahead: '(\s+{{macro_identifier}})*\s*(:\s*({{path_lookahead}}|{{visibility_modifiers}}|,|\s|<[^;]*>)+)?;'
+ non_func_keywords: 'if|for|switch|while|decltype|sizeof|__declspec|__attribute__|typeid|alignof|alignas|static_assert'
+
+ format_spec: |-
+ (?x:
+ (?:.? [<>=^])? # fill align
+ [ +-]? # sign
+ \#? # alternate form
+ # technically, octal and hexadecimal integers are also supported as 'width', but rarely used
+ \d* # width
+ ,? # thousands separator
+ (?:\.\d+)? # precision
+ [bcdeEfFgGnosxX%]? # type
+ )
+
+contexts:
+ main:
+ - include: preprocessor-global
+ - include: global
+
+ #############################################################################
+ # Reusable contexts
+ #
+ # The follow contexts are currently constructed to be reused in the
+ # Objetive-C++ syntax. They are specifically constructed to not push into
+ # sub-contexts, which ensures that Objective-C++ code isn't accidentally
+ # lexed as plain C++.
+ #
+ # The "unique-*" contexts are additions that C++ makes over C, and thus can
+ # be directly reused in Objective-C++ along with contexts from Objective-C
+ # and C.
+ #############################################################################
+
+ unique-late-expressions:
+ # This is highlighted after all of the other control keywords
+ # to allow operator overloading to be lexed properly
+ - match: \boperator\b
+ scope: keyword.control.c++
+
+ unique-modifiers:
+ - match: \b({{modifiers}})\b
+ scope: storage.modifier.c++
+
+ unique-variables:
+ - match: \bthis\b
+ scope: variable.language.c++
+ # common C++ instance var naming idiom -- fMemberName
+ - match: '\b(f|m)[[:upper:]]\w*\b'
+ scope: variable.other.readwrite.member.c++
+ # common C++ instance var naming idiom -- m_member_name
+ - match: '\bm_[[:alnum:]_]+\b'
+ scope: variable.other.readwrite.member.c++
+
+ unique-constants:
+ - match: \bnullptr\b
+ scope: constant.language.c++
+
+ unique-keywords:
+ - match: \busing\b
+ scope: keyword.control.c++
+ - match: \bbreak\b
+ scope: keyword.control.flow.break.c++
+ - match: \bcontinue\b
+ scope: keyword.control.flow.continue.c++
+ - match: \bgoto\b
+ scope: keyword.control.flow.goto.c++
+ - match: \breturn\b
+ scope: keyword.control.flow.return.c++
+ - match: \bthrow\b
+ scope: keyword.control.flow.throw.c++
+ - match: \b({{control_keywords}})\b
+ scope: keyword.control.c++
+ - match: '\bdelete\b(\s*\[\])?|\bnew\b(?!])'
+ scope: keyword.control.c++
+ - match: \b({{operator_keywords}})\b
+ scope: keyword.operator.word.c++
+
+ unique-types:
+ - match: \b(char16_t|char32_t|wchar_t|nullptr_t)\b
+ scope: storage.type.c++
+ - match: \bclass\b
+ scope: storage.type.c++
+
+ unique-strings:
+ - match: '((?:L|u8|u|U)?R)("([^\(\)\\ ]{0,16})\()'
+ captures:
+ 1: storage.type.string.c++
+ 2: punctuation.definition.string.begin.c++
+ push:
+ - meta_scope: string.quoted.double.c++
+ - match: '\)\3"'
+ scope: punctuation.definition.string.end.c++
+ pop: true
+ - match: '\{\{|\}\}'
+ scope: constant.character.escape.c++
+ - include: formatting-syntax
+
+ unique-numbers:
+ - match: |-
+ (?x)
+ (?:
+ # floats
+ (?:
+ (?:\b\d(?:[\d']*\d)?\.\d(?:[\d']*\d)?|\B\.\d(?:[\d']*\d)?)(?:[Ee][+-]?\d(?:[\d']*\d)?)?(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))?\b
+ |
+ (?:\b\d(?:[\d']*\d)?\.)(?:\B|(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))\b|(?:[Ee][+-]?\d(?:[\d']*\d)?)(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))?\b)
+ |
+ \b\d(?:[\d']*\d)?(?:[Ee][+-]?\d(?:[\d']*\d)?)(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))?\b
+ )
+ |
+ # ints
+ \b(?:
+ (?:
+ # dec
+ [1-9](?:[\d']*\d)?
+ |
+ # oct
+ 0(?:[0-7']*[0-7])?
+ |
+ # hex
+ 0[Xx][\da-fA-F](?:[\da-fA-F']*[\da-fA-F])?
+ |
+ # bin
+ 0[Bb][01](?:[01']*[01])?
+ )
+ # int suffixes
+ (?:(?:l{1,2}|L{1,2})[uU]?|[uU](?:l{0,2}|L{0,2})|(?:i[fl]?|h|min|[mun]?s|_\w*))?)\b
+ )
+ (?!\.) # Number must not be followed by a decimal point
+ scope: constant.numeric.c++
+
+ identifiers:
+ - match: '{{identifier}}\s*(::)\s*'
+ captures:
+ 1: punctuation.accessor.c++
+ - match: '(?:(::)\s*)?{{identifier}}'
+ captures:
+ 1: punctuation.accessor.c++
+
+ function-specifiers:
+ - match: \b(const|final|noexcept|override)\b
+ scope: storage.modifier.c++
+
+ #############################################################################
+ # The following are C++-specific contexts that should not be reused. This is
+ # because they push into subcontexts and use variables that are C++-specific.
+ #############################################################################
+
+ ## Common context layout
+
+ global:
+ - match: '(?=\btemplate\b)'
+ push:
+ - include: template
+ - match: (?=\S)
+ set: global-modifier
+ - include: namespace
+ - include: keywords-angle-brackets
+ - match: '(?={{path_lookahead}}\s*<)'
+ push: global-modifier
+ # Take care of comments just before a function definition.
+ - match: /\*
+ scope: punctuation.definition.comment.c
+ push:
+ - - match: \s*(?=\w)
+ set: global-modifier
+ - match: ""
+ pop: true
+ - - meta_scope: comment.block.c
+ - match: \*/
+ scope: punctuation.definition.comment.c
+ pop: true
+ - include: early-expressions
+ - match: ^\s*\b(extern)(?=\s+"C(\+\+)?")
+ scope: storage.modifier.c++
+ push:
+ - include: comments
+ - include: strings
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ set:
+ - meta_scope: meta.extern-c.c++
+ - match: '^\s*(#\s*ifdef)\s*__cplusplus\s*'
+ scope: meta.preprocessor.c++
+ captures:
+ 1: keyword.control.import.c++
+ set:
+ - match: '\}'
+ scope: punctuation.section.block.end.c++
+ pop: true
+ - include: preprocessor-global
+ - include: global
+ - match: '\}'
+ scope: punctuation.section.block.end.c++
+ pop: true
+ - include: preprocessor-global
+ - include: global
+ - match: (?=\S)
+ set: global-modifier
+ - match: ^\s*(?=\w)
+ push: global-modifier
+ - include: late-expressions
+
+ statements:
+ - include: preprocessor-statements
+ - include: scope:source.c#label
+ - include: expressions
+
+ expressions:
+ - include: early-expressions
+ - include: late-expressions
+
+ early-expressions:
+ - include: early-expressions-before-generic-type
+ - include: generic-type
+ - include: early-expressions-after-generic-type
+
+ early-expressions-before-generic-type:
+ - include: preprocessor-expressions
+ - include: comments
+ - include: case-default
+ - include: typedef
+ - include: keywords-angle-brackets
+ - include: keywords-parens
+ - include: keywords
+ - include: numbers
+ # Prevent a '<' from getting scoped as the start of another template
+ # parameter list, if in reality a less-than-or-equals sign is meant.
+ - match: <=
+ scope: keyword.operator.comparison.c
+
+ early-expressions-after-generic-type:
+ - include: members-arrow
+ - include: operators
+ - include: members-dot
+ - include: strings
+ - include: parens
+ - include: brackets
+ - include: block
+ - include: variables
+ - include: constants
+ - match: ','
+ scope: punctuation.separator.c++
+ - match: '\)|\}'
+ scope: invalid.illegal.stray-bracket-end.c++
+
+ expressions-minus-generic-type:
+ - include: early-expressions-before-generic-type
+ - include: angle-brackets
+ - include: early-expressions-after-generic-type
+ - include: late-expressions
+
+ expressions-minus-generic-type-function-call:
+ - include: early-expressions-before-generic-type
+ - include: angle-brackets
+ - include: early-expressions-after-generic-type
+ - include: late-expressions-before-function-call
+ - include: identifiers
+ - match: ';'
+ scope: punctuation.terminator.c++
+
+ late-expressions:
+ - include: late-expressions-before-function-call
+ - include: function-call
+ - include: identifiers
+ - match: ';'
+ scope: punctuation.terminator.c++
+
+ late-expressions-before-function-call:
+ - include: unique-late-expressions
+ - include: modifiers-parens
+ - include: modifiers
+ - include: types
+
+ expressions-minus-function-call:
+ - include: early-expressions
+ - include: late-expressions-before-function-call
+ - include: identifiers
+ - match: ';'
+ scope: punctuation.terminator.c++
+
+ comments:
+ - include: scope:source.c#comments
+
+ operators:
+ - include: scope:source.c#operators
+
+ modifiers:
+ - include: unique-modifiers
+ - include: scope:source.c#modifiers
+
+ variables:
+ - include: unique-variables
+ - include: scope:source.c#variables
+
+ constants:
+ - include: unique-constants
+ - include: scope:source.c#constants
+
+ keywords:
+ - include: unique-keywords
+ - include: scope:source.c#keywords
+
+ types:
+ - include: unique-types
+ - include: types-parens
+ - include: scope:source.c#types
+
+ strings:
+ - include: unique-strings
+ - match: '(L|u8|u|U)?(")'
+ captures:
+ 1: storage.type.string.c++
+ 2: punctuation.definition.string.begin.c++
+ push:
+ - meta_scope: string.quoted.double.c++
+ - match: '"'
+ scope: punctuation.definition.string.end.c++
+ pop: true
+ - include: scope:source.c#string_escaped_char
+ - match: |-
+ (?x)%
+ (\d+\$)? # field (argument #)
+ [#0\- +']* # flags
+ [,;:_]? # separator character (AltiVec)
+ ((-?\d+)|\*(-?\d+\$)?)? # minimum field width
+ (\.((-?\d+)|\*(-?\d+\$)?)?)? # precision
+ (hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier
+ (\[[^\]]+\]|[am]s|[diouxXDOUeEfFgGaACcSspn%]) # conversion type
+ scope: constant.other.placeholder.c++
+ - match: '\{\{|\}\}'
+ scope: constant.character.escape.c++
+ - include: formatting-syntax
+ - include: scope:source.c#strings
+
+ formatting-syntax:
+ # https://docs.python.org/3.6/library/string.html#formatstrings
+ - match: |- # simple form
+ (?x)
+ (\{)
+ (?: [\w.\[\]]+)? # field_name
+ ( ! [ars])? # conversion
+ ( : (?:{{format_spec}}| # format_spec OR
+ [^}%]*%.[^}]*) # any format-like string
+ )?
+ (\})
+ scope: constant.other.placeholder.c++
+ captures:
+ 1: punctuation.definition.placeholder.begin.c++
+ 2: storage.modifier.c++onversion.c++
+ 3: constant.other.format-spec.c++
+ 4: punctuation.definition.placeholder.end.c++
+ - match: \{(?=[^\}"']+\{[^"']*\}) # complex (nested) form
+ scope: punctuation.definition.placeholder.begin.c++
+ push:
+ - meta_scope: constant.other.placeholder.c++
+ - match: \}
+ scope: punctuation.definition.placeholder.end.c++
+ pop: true
+ - match: '[\w.\[\]]+'
+ - match: '![ars]'
+ scope: storage.modifier.conversion.c++
+ - match: ':'
+ push:
+ - meta_scope: meta.format-spec.c++ constant.other.format-spec.c++
+ - match: (?=\})
+ pop: true
+ - include: formatting-syntax
+
+ numbers:
+ - include: unique-numbers
+ - include: scope:source.c#numbers
+
+ ## C++-specific contexts
+
+ case-default:
+ - match: '\b(default|case)\b'
+ scope: keyword.control.c++
+ push:
+ - match: (?=[);,])
+ pop: true
+ - match: ':'
+ scope: punctuation.separator.c++
+ pop: true
+ - include: expressions
+
+ modifiers-parens:
+ - match: '\b(alignas)\b\s*(\()'
+ captures:
+ 1: storage.modifier.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push:
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ - match: \b(__attribute__)\s*(\(\()
+ captures:
+ 1: storage.modifier.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push :
+ - meta_scope: meta.attribute.c++
+ - meta_content_scope: meta.group.c++
+ - include: parens
+ - include: strings
+ - match: \)\)
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - match: \b(__declspec)(\()
+ captures:
+ 1: storage.modifier.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push:
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - match: '\b(align|allocate|code_seg|deprecated|property|uuid)\b\s*(\()'
+ captures:
+ 1: storage.modifier.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push:
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: numbers
+ - include: strings
+ - match: \b(get|put)\b
+ scope: variable.parameter.c++
+ - match: ','
+ scope: punctuation.separator.c++
+ - match: '='
+ scope: keyword.operator.assignment.c++
+ - match: '\b(appdomain|deprecated|dllimport|dllexport|jintrinsic|naked|noalias|noinline|noreturn|nothrow|novtable|process|restrict|safebuffers|selectany|thread)\b'
+ scope: constant.other.c++
+
+ types-parens:
+ - match: '\b(decltype)\b\s*(\()'
+ captures:
+ 1: storage.type.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push:
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+
+ keywords-angle-brackets:
+ - match: \b({{casts}})\b\s*
+ scope: keyword.operator.word.cast.c++
+ push:
+ - match: '>'
+ scope: punctuation.section.generic.end.c++
+ pop: true
+ - match: '<'
+ scope: punctuation.section.generic.begin.c++
+ push:
+ - match: '(?=>)'
+ pop: true
+ - include: expressions-minus-generic-type-function-call
+
+ keywords-parens:
+ - match: '\b(alignof|typeid|static_assert|sizeof)\b\s*(\()'
+ captures:
+ 1: keyword.operator.word.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push:
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+
+ namespace:
+ - match: '\b(using)\s+(namespace)\s+(?={{path_lookahead}})'
+ captures:
+ 1: keyword.control.c++
+ 2: keyword.control.c++
+ push:
+ - include: identifiers
+ - match: ''
+ pop: true
+ - match: '\b(namespace)\s+(?=({{path_lookahead}})?(?!\s*[;,]))'
+ scope: meta.namespace.c++
+ captures:
+ 1: keyword.control.c++
+ push:
+ - meta_content_scope: meta.namespace.c++ entity.name.namespace.c++
+ - include: identifiers
+ - match: ''
+ set:
+ - meta_scope: meta.namespace.c++
+ - include: comments
+ - match: '='
+ scope: keyword.operator.alias.c++
+ - match: '(?=;)'
+ pop: true
+ - match: '\}'
+ scope: meta.block.c++ punctuation.section.block.end.c++
+ pop: true
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ push:
+ - meta_scope: meta.block.c++
+ - match: '(?=\})'
+ pop: true
+ - include: preprocessor-global
+ - include: global
+ - include: expressions
+
+ template-common:
+ # Exit the template scope if we hit some basic invalid characters. This
+ # helps when a user is in the middle of typing their template types and
+ # prevents re-highlighting the whole file until the next > is found.
+ - match: (?=[{};])
+ pop: true
+ - include: expressions
+
+ template:
+ - match: \btemplate\b
+ scope: storage.type.template.c++
+ push:
+ - meta_scope: meta.template.c++
+ # Explicitly include comments here at the top, in order to NOT match the
+ # \S lookahead in the case of comments.
+ - include: comments
+ - match: <
+ scope: punctuation.section.generic.begin.c++
+ set:
+ - meta_content_scope: meta.template.c++
+ - match: '>'
+ scope: meta.template.c++ punctuation.section.generic.end.c++
+ pop: true
+ - match: \.{3}
+ scope: keyword.operator.variadic.c++
+ - match: \b(typename|{{before_tag}})\b
+ scope: storage.type.c++
+ - include: template # include template here for nested templates
+ - include: template-common
+ - match: (?=\S)
+ set:
+ - meta_content_scope: meta.template.c++
+ - match: \b({{before_tag}})\b
+ scope: storage.type.c++
+ - include: template-common
+
+ generic-type:
+ - match: '(?=(?!template){{path_lookahead}}\s*{{generic_lookahead}}\s*\()'
+ push:
+ - meta_scope: meta.function-call.c++
+ - match: \btemplate\b
+ scope: storage.type.template.c++
+ - match: '(?:(::)\s*)?{{identifier}}\s*(::)\s*'
+ captures:
+ 1: punctuation.accessor.double-colon.c++
+ 2: punctuation.accessor.double-colon.c++
+ - match: (?:(::)\s*)?({{identifier}})\s*(<)
+ captures:
+ 1: punctuation.accessor.double-colon.c++
+ 2: variable.function.c++
+ 3: punctuation.section.generic.begin.c++
+ push:
+ - match: '>'
+ scope: punctuation.section.generic.end.c++
+ pop: true
+ - include: expressions-minus-generic-type-function-call
+ - match: (?:(::)\s*)?({{identifier}})\s*(\()
+ captures:
+ 1: punctuation.accessor.double-colon.c++
+ 2: variable.function.c++
+ 3: punctuation.section.group.begin.c++
+ set:
+ - meta_scope: meta.function-call.c++
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ - include: angle-brackets
+ - match: '\('
+ scope: meta.group.c++ punctuation.section.group.begin.c++
+ set:
+ - meta_scope: meta.function-call.c++
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ - match: '(?=(?!template){{path_lookahead}}\s*{{generic_lookahead}})'
+ push:
+ - include: identifiers
+ - match: '<'
+ scope: punctuation.section.generic.begin.c++
+ set:
+ - match: '>'
+ scope: punctuation.section.generic.end.c++
+ pop: true
+ - include: expressions-minus-generic-type-function-call
+
+ angle-brackets:
+ - match: '<(?!<)'
+ scope: punctuation.section.generic.begin.c++
+ push:
+ - match: '>'
+ scope: punctuation.section.generic.end.c++
+ pop: true
+ - include: expressions-minus-generic-type-function-call
+
+ block:
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ push:
+ - meta_scope: meta.block.c++
+ - match: (?=^\s*#\s*(elif|else|endif)\b)
+ pop: true
+ - match: '\}'
+ scope: punctuation.section.block.end.c++
+ pop: true
+ - include: statements
+
+ function-call:
+ - match: (?={{path_lookahead}}\s*\()
+ push:
+ - meta_scope: meta.function-call.c++
+ - include: scope:source.c#c99
+ - match: '(?:(::)\s*)?{{identifier}}\s*(::)\s*'
+ scope: variable.function.c++
+ captures:
+ 1: punctuation.accessor.c++
+ 2: punctuation.accessor.c++
+ - match: '(?:(::)\s*)?{{identifier}}'
+ scope: variable.function.c++
+ captures:
+ 1: punctuation.accessor.c++
+ - match: '\('
+ scope: meta.group.c++ punctuation.section.group.begin.c++
+ set:
+ - meta_content_scope: meta.function-call.c++ meta.group.c++
+ - match: '\)'
+ scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+
+ members-inside-function-call:
+ - meta_content_scope: meta.method-call.c++ meta.group.c++
+ - match: \)
+ scope: meta.method-call.c++ meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+
+ members-after-accessor-junction:
+ # After we've seen an accessor (dot or arrow), this context decides what
+ # kind of entity we're accessing.
+ - include: comments
+ - match: \btemplate\b
+ scope: meta.method-call.c++ storage.type.template.c++
+ # Guaranteed to be a template member function call after we match this
+ set:
+ - meta_content_scope: meta.method-call.c++
+ - include: comments
+ - match: '{{identifier}}'
+ scope: variable.function.member.c++
+ set:
+ - meta_content_scope: meta.method-call.c++
+ - match: \(
+ scope: meta.group.c++ punctuation.section.group.begin.c++
+ set: members-inside-function-call
+ - include: comments
+ - include: angle-brackets
+ - match: (?=\S) # safety pop
+ pop: true
+ - match: (?=\S) # safety pop
+ pop: true
+ # Operator overloading
+ - match: '({{operator_method_name}})\s*(\()'
+ captures:
+ 0: meta.method-call.c++
+ 1: variable.function.member.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ set: members-inside-function-call
+ # Non-templated member function call
+ - match: (~?{{identifier}})\s*(\()
+ captures:
+ 0: meta.method-call.c++
+ 1: variable.function.member.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ set: members-inside-function-call
+ # Templated member function call
+ - match: (~?{{identifier}})\s*(?={{generic_lookahead}})
+ captures:
+ 1: variable.function.member.c++
+ set:
+ - meta_scope: meta.method-call.c++
+ - match: <
+ scope: punctuation.section.generic.begin.c++
+ set:
+ - meta_content_scope: meta.method-call.c++
+ - match: '>'
+ scope: punctuation.section.generic.end.c++
+ set:
+ - meta_content_scope: meta.method-call.c++
+ - include: comments
+ - match: \(
+ scope: punctuation.section.group.begin.c++
+ set: members-inside-function-call
+ - match: (?=\S) # safety pop
+ pop: true
+ - include: expressions
+ # Explicit base-class access
+ - match: ({{identifier}})\s*(::)
+ captures:
+ 1: variable.other.base-class.c++
+ 2: punctuation.accessor.double-colon.c++
+ set: members-after-accessor-junction # reset
+ # Just a regular member variable
+ - match: '{{identifier}}'
+ scope: variable.other.readwrite.member.c++
+ pop: true
+
+ members-dot:
+ - include: scope:source.c#access-illegal
+ # No lookahead required because members-dot goes after operators in the
+ # early-expressions-after-generic-type context. This means triple dots
+ # (i.e. "..." or "variadic") is attempted first.
+ - match: \.
+ scope: punctuation.accessor.dot.c++
+ push: members-after-accessor-junction
+
+ members-arrow:
+ # This needs to be before operators in the
+ # early-expressions-after-generic-type context because otherwise the "->"
+ # from the C language will match.
+ - match: ->
+ scope: punctuation.accessor.arrow.c++
+ push: members-after-accessor-junction
+
+ typedef:
+ - match: \btypedef\b
+ scope: storage.type.c++
+ push:
+ - match: ({{identifier}})?\s*(?=;)
+ captures:
+ 1: entity.name.type.typedef.c++
+ pop: true
+ - match: \b(struct)\s+({{identifier}})\b
+ captures:
+ 1: storage.type.c++
+ - include: expressions-minus-generic-type
+
+ parens:
+ - match: \(
+ scope: punctuation.section.group.begin.c++
+ push:
+ - meta_scope: meta.group.c++
+ - match: \)
+ scope: punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+
+ brackets:
+ - match: \[
+ scope: punctuation.section.brackets.begin.c++
+ push:
+ - meta_scope: meta.brackets.c++
+ - match: \]
+ scope: punctuation.section.brackets.end.c++
+ pop: true
+ - include: expressions
+
+ function-trailing-return-type:
+ - match: '{{non_angle_brackets}}'
+ pop: true
+ - include: angle-brackets
+ - include: types
+ - include: modifiers-parens
+ - include: modifiers
+ - include: identifiers
+ - match: \*|&
+ scope: keyword.operator.c++
+ - include: function-trailing-return-type-parens
+ - match: '(?=\S)'
+ pop: true
+
+ function-trailing-return-type-parens:
+ - match: \(
+ scope: punctuation.section.group.begin.c++
+ push:
+ - meta_scope: meta.group.c++
+ - match: \)
+ scope: punctuation.section.group.end.c++
+ pop: true
+ - include: function-trailing-return-type
+
+ ## Detection of function and data structure definitions at the global level
+
+ global-modifier:
+ - include: comments
+ - include: modifiers-parens
+ - include: modifiers
+ # Constructors and destructors don't have a type
+ - match: '(?={{path_lookahead}}\s*::\s*{{identifier}}\s*(\(|$))'
+ set:
+ - meta_content_scope: meta.function.c++ entity.name.function.constructor.c++
+ - include: identifiers
+ - match: '(?=[^\w\s])'
+ set: function-definition-params
+ - match: '(?={{path_lookahead}}\s*::\s*~{{identifier}}\s*(\(|$))'
+ set:
+ - meta_content_scope: meta.function.c++ entity.name.function.destructor.c++
+ - include: identifiers
+ - match: '~{{identifier}}'
+ - match: '(?=[^\w\s])'
+ set: function-definition-params
+ # If we see a path ending in :: before a newline, we don't know if it is
+ # a constructor or destructor, or a long return type, so we are just going
+ # to treat it like a regular function. Most likely it is a constructor,
+ # since it doesn't seem most developers would create such a long typename.
+ - match: '(?={{path_lookahead}}\s*::\s*$)'
+ set:
+ - meta_content_scope: meta.function.c++ entity.name.function.c++
+ - include: identifiers
+ - match: '~{{identifier}}'
+ - match: '(?=[^\w\s])'
+ set: function-definition-params
+ - include: unique-strings
+ - match: '(?=\S)'
+ set: global-type
+
+ global-type:
+ - include: comments
+ - match: \*|&
+ scope: keyword.operator.c++
+ - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}}|operator)\b)'
+ pop: true
+ - match: '(?=\s)'
+ set: global-maybe-function
+ # If a class/struct/enum followed by a name that is not a macro or declspec
+ # then this is likely a return type of a function. This is uncommon.
+ - match: |-
+ (?x:
+ ({{before_tag}})
+ \s+
+ (?=
+ (?![[:upper:][:digit:]_]+\b|__declspec|{{before_tag}})
+ {{path_lookahead}}
+ (\s+{{identifier}}\s*\(|\s*[*&])
+ )
+ )
+ captures:
+ 1: storage.type.c++
+ set:
+ - include: identifiers
+ - match: ''
+ set: global-maybe-function
+ # The previous match handles return types of struct/enum/etc from a func,
+ # there this one exits the context to allow matching an actual struct/class
+ - match: '(?=\b({{before_tag}})\b)'
+ set: data-structures
+ - match: '(?=\b({{casts}})\b\s*<)'
+ pop: true
+ - match: '{{non_angle_brackets}}'
+ pop: true
+ - include: angle-brackets
+ - include: types
+ # Allow a macro call
+ - match: '({{identifier}})\s*(\()(?=[^\)]+\))'
+ captures:
+ 1: variable.function.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push:
+ - meta_scope: meta.function-call.c++
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ - match: '(?={{path_lookahead}}\s*\()'
+ set:
+ - include: function-call
+ - match: ''
+ pop: true
+ - include: variables
+ - include: constants
+ - include: identifiers
+ - match: (?=\W)
+ pop: true
+
+ global-maybe-function:
+ - include: comments
+ # Consume pointer info, macros and any type info that was offset by macros
+ - match: \*|&
+ scope: keyword.operator.c++
+ - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}})\b)'
+ pop: true
+ - match: '\b({{type_qualifier}})\b'
+ scope: storage.modifier.c++
+ - match: '{{non_angle_brackets}}'
+ pop: true
+ - include: angle-brackets
+ - include: types
+ - include: modifiers-parens
+ - include: modifiers
+ # All uppercase identifier just before a newline is most likely a macro
+ - match: '[[:upper:][:digit:]_]+\s*$'
+ # Operator overloading
+ - match: '(?=({{path_lookahead}}\s*(?:{{generic_lookahead}})?::\s*)?{{operator_method_name}}\s*(\(|$))'
+ set:
+ - meta_content_scope: meta.function.c++ entity.name.function.c++
+ - include: identifiers
+ - match: '(?=\s*(\(|$))'
+ set: function-definition-params
+ # Identifier that is not the function name - likely a macro or type
+ - match: '(?={{path_lookahead}}([ \t]+|[*&])(?!\s*(<|::|\(|$)))'
+ push:
+ - include: identifiers
+ - match: ''
+ pop: true
+ # Real function definition
+ - match: '(?={{path_lookahead}}({{generic_lookahead}}({{path_lookahead}})?)\s*(\(|$))'
+ set: [function-definition-params, global-function-identifier-generic]
+ - match: '(?={{path_lookahead}}\s*(\(|$))'
+ set: [function-definition-params, global-function-identifier]
+ - match: '(?={{path_lookahead}}\s*::\s*$)'
+ set: [function-definition-params, global-function-identifier]
+ - match: '(?=\S)'
+ pop: true
+
+ global-function-identifier-generic:
+ - include: angle-brackets
+ - match: '::'
+ scope: punctuation.accessor.c++
+ - match: '(?={{identifier}}<.*>\s*\()'
+ push:
+ - meta_content_scope: entity.name.function.c++
+ - include: identifiers
+ - match: '(?=<)'
+ pop: true
+ - match: '(?={{identifier}}\s*\()'
+ push:
+ - meta_content_scope: entity.name.function.c++
+ - include: identifiers
+ - match: ''
+ pop: true
+ - match: '(?=\()'
+ pop: true
+
+ global-function-identifier:
+ - meta_content_scope: entity.name.function.c++
+ - include: identifiers
+ - match: '(?=\S)'
+ pop: true
+
+ function-definition-params:
+ - meta_content_scope: meta.function.c++
+ - include: comments
+ - match: '(?=\()'
+ set:
+ - match: \(
+ scope: meta.function.parameters.c++ meta.group.c++ punctuation.section.group.begin.c++
+ set:
+ - meta_content_scope: meta.function.parameters.c++ meta.group.c++
+ - match : \)
+ scope: punctuation.section.group.end.c++
+ set: function-definition-continue
+ - match: '\bvoid\b'
+ scope: storage.type.c++
+ - match: '{{identifier}}(?=\s*(\[|,|\)|=))'
+ scope: variable.parameter.c++
+ - match: '='
+ scope: keyword.operator.assignment.c++
+ push:
+ - match: '(?=,|\))'
+ pop: true
+ - include: expressions-minus-generic-type
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: expressions-minus-generic-type
+ - include: scope:source.c#preprocessor-line-continuation
+ - match: (?=\S)
+ pop: true
+
+ function-definition-continue:
+ - meta_content_scope: meta.function.c++
+ - include: comments
+ - match: '(?=;)'
+ pop: true
+ - match: '->'
+ scope: punctuation.separator.c++
+ set: function-definition-trailing-return
+ - include: function-specifiers
+ - match: '='
+ scope: keyword.operator.assignment.c++
+ - match: '&'
+ scope: keyword.operator.c++
+ - match: \b0\b
+ scope: constant.numeric.c++
+ - match: \b(default|delete)\b
+ scope: storage.modifier.c++
+ - match: '(?=\{)'
+ set: function-definition-body
+ - match: '(?=\S)'
+ pop: true
+
+ function-definition-trailing-return:
+ - include: comments
+ - match: '(?=;)'
+ pop: true
+ - match: '(?=\{)'
+ set: function-definition-body
+ - include: function-specifiers
+ - include: function-trailing-return-type
+
+ function-definition-body:
+ - meta_content_scope: meta.function.c++ meta.block.c++
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ set:
+ - meta_content_scope: meta.function.c++ meta.block.c++
+ - match: '\}'
+ scope: meta.function.c++ meta.block.c++ punctuation.section.block.end.c++
+ pop: true
+ - match: (?=^\s*#\s*(elif|else|endif)\b)
+ pop: true
+ - match: '(?=({{before_tag}})([^(;]+$|.*\{))'
+ push: data-structures
+ - include: statements
+
+ ## Data structures including classes, structs, unions and enums
+
+ data-structures:
+ - match: '\bclass\b'
+ scope: storage.type.c++
+ set: data-structures-class-definition
+ # Detect variable type definitions using struct/enum/union followed by a tag
+ - match: '\b({{before_tag}})(?=\s+{{path_lookahead}}\s+{{path_lookahead}}\s*[=;\[])'
+ scope: storage.type.c++
+ - match: '\bstruct\b'
+ scope: storage.type.c++
+ set: data-structures-struct-definition
+ - match: '\benum(\s+(class|struct))?\b'
+ scope: storage.type.c++
+ set: data-structures-enum-definition
+ - match: '\bunion\b'
+ scope: storage.type.c++
+ set: data-structures-union-definition
+ - match: '(?=\S)'
+ pop: true
+
+ preprocessor-workaround-eat-macro-before-identifier:
+ # Handle macros so they aren't matched as the class name
+ - match: ({{macro_identifier}})(?=\s+~?{{identifier}})
+ captures:
+ 1: meta.assumed-macro.c
+
+ data-structures-class-definition:
+ - meta_scope: meta.class.c++
+ - include: data-structures-definition-common-begin
+ - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})'
+ scope: entity.name.class.forward-decl.c++
+ set: data-structures-class-definition-after-identifier
+ - match: '{{identifier}}'
+ scope: entity.name.class.c++
+ set: data-structures-class-definition-after-identifier
+ - match: '(?=[:{])'
+ set: data-structures-class-definition-after-identifier
+ - match: '(?=;)'
+ pop: true
+
+ data-structures-class-definition-after-identifier:
+ - meta_content_scope: meta.class.c++
+ - include: data-structures-definition-common-begin
+ # No matching of identifiers since they should all be macros at this point
+ - include: data-structures-definition-common-end
+ - match: '\{'
+ scope: meta.block.c++ punctuation.section.block.begin.c++
+ set:
+ - meta_content_scope: meta.class.c++ meta.block.c++
+ - match: '\}'
+ scope: meta.class.c++ meta.block.c++ punctuation.section.block.end.c++
+ pop: true
+ - include: data-structures-body
+
+ data-structures-struct-definition:
+ - meta_scope: meta.struct.c++
+ - include: data-structures-definition-common-begin
+ - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})'
+ scope: entity.name.struct.forward-decl.c++
+ set: data-structures-struct-definition-after-identifier
+ - match: '{{identifier}}'
+ scope: entity.name.struct.c++
+ set: data-structures-struct-definition-after-identifier
+ - match: '(?=[:{])'
+ set: data-structures-struct-definition-after-identifier
+ - match: '(?=;)'
+ pop: true
+
+ data-structures-struct-definition-after-identifier:
+ - meta_content_scope: meta.struct.c++
+ - include: data-structures-definition-common-begin
+ # No matching of identifiers since they should all be macros at this point
+ - include: data-structures-definition-common-end
+ - match: '\{'
+ scope: meta.block.c++ punctuation.section.block.begin.c++
+ set:
+ - meta_content_scope: meta.struct.c++ meta.block.c++
+ - match: '\}'
+ scope: meta.struct.c++ meta.block.c++ punctuation.section.block.end.c++
+ pop: true
+ - include: data-structures-body
+
+ data-structures-enum-definition:
+ - meta_scope: meta.enum.c++
+ - include: data-structures-definition-common-begin
+ - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})'
+ scope: entity.name.enum.forward-decl.c++
+ set: data-structures-enum-definition-after-identifier
+ - match: '{{identifier}}'
+ scope: entity.name.enum.c++
+ set: data-structures-enum-definition-after-identifier
+ - match: '(?=[:{])'
+ set: data-structures-enum-definition-after-identifier
+ - match: '(?=;)'
+ pop: true
+
+ data-structures-enum-definition-after-identifier:
+ - meta_content_scope: meta.enum.c++
+ - include: data-structures-definition-common-begin
+ # No matching of identifiers since they should all be macros at this point
+ - include: data-structures-definition-common-end
+ - match: '\{'
+ scope: meta.block.c++ punctuation.section.block.begin.c++
+ set:
+ - meta_content_scope: meta.enum.c++ meta.block.c++
+ # Enums don't support methods so we have a simplified body
+ - match: '\}'
+ scope: meta.enum.c++ meta.block.c++ punctuation.section.block.end.c++
+ pop: true
+ - include: statements
+
+ data-structures-union-definition:
+ - meta_scope: meta.union.c++
+ - include: data-structures-definition-common-begin
+ - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})'
+ scope: entity.name.union.forward-decl.c++
+ set: data-structures-union-definition-after-identifier
+ - match: '{{identifier}}'
+ scope: entity.name.union.c++
+ set: data-structures-union-definition-after-identifier
+ - match: '(?=[{])'
+ set: data-structures-union-definition-after-identifier
+ - match: '(?=;)'
+ pop: true
+
+ data-structures-union-definition-after-identifier:
+ - meta_content_scope: meta.union.c++
+ - include: data-structures-definition-common-begin
+ # No matching of identifiers since they should all be macros at this point
+ # Unions don't support base classes
+ - include: angle-brackets
+ - match: '\{'
+ scope: meta.block.c++ punctuation.section.block.begin.c++
+ set:
+ - meta_content_scope: meta.union.c++ meta.block.c++
+ - match: '\}'
+ scope: meta.union.c++ meta.block.c++ punctuation.section.block.end.c++
+ pop: true
+ - include: data-structures-body
+ - match: '(?=;)'
+ pop: true
+
+ data-structures-definition-common-begin:
+ - include: comments
+ - match: '(?=\b(?:{{before_tag}}|{{control_keywords}})\b)'
+ pop: true
+ - include: preprocessor-other
+ - include: modifiers-parens
+ - include: modifiers
+ - include: preprocessor-workaround-eat-macro-before-identifier
+
+ data-structures-definition-common-end:
+ - include: angle-brackets
+ - match: \bfinal\b
+ scope: storage.modifier.c++
+ - match: ':'
+ scope: punctuation.separator.c++
+ push:
+ - include: comments
+ - include: preprocessor-other
+ - include: modifiers-parens
+ - include: modifiers
+ - match: '\b(virtual|{{visibility_modifiers}})\b'
+ scope: storage.modifier.c++
+ - match: (?={{path_lookahead}})
+ push:
+ - meta_scope: entity.other.inherited-class.c++
+ - include: identifiers
+ - match: ''
+ pop: true
+ - include: angle-brackets
+ - match: ','
+ scope: punctuation.separator.c++
+ - match: (?=\{|;)
+ pop: true
+ - match: '(?=;)'
+ pop: true
+
+ data-structures-body:
+ - include: preprocessor-data-structures
+ - match: '(?=\btemplate\b)'
+ push:
+ - include: template
+ - match: (?=\S)
+ set: data-structures-modifier
+ - include: typedef
+ - match: \b({{visibility_modifiers}})\s*(:)(?!:)
+ captures:
+ 1: storage.modifier.c++
+ 2: punctuation.section.class.c++
+ - match: '^\s*(?=(?:~?\w+|::))'
+ push: data-structures-modifier
+ - include: expressions-minus-generic-type
+
+ data-structures-modifier:
+ - match: '\bfriend\b'
+ scope: storage.modifier.c++
+ push:
+ - match: (?=;)
+ pop: true
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ set:
+ - meta_scope: meta.block.c++
+ - match: '\}'
+ scope: punctuation.section.block.end.c++
+ pop: true
+ - include: statements
+ - match: '\b({{before_tag}})\b'
+ scope: storage.type.c++
+ - include: expressions-minus-function-call
+ - include: comments
+ - include: modifiers-parens
+ - include: modifiers
+ - match: '\bstatic_assert(?=\s*\()'
+ scope: meta.static-assert.c++ keyword.operator.word.c++
+ push:
+ - match: '\('
+ scope: meta.group.c++ punctuation.section.group.begin.c++
+ set:
+ - meta_content_scope: meta.function-call.c++ meta.group.c++
+ - match: '\)'
+ scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ # Destructor
+ - match: '(?:{{identifier}}\s*(::)\s*)?~{{identifier}}(?=\s*(\(|$))'
+ scope: meta.method.destructor.c++ entity.name.function.destructor.c++
+ captures:
+ 1: punctuation.accessor.c++
+ set: method-definition-params
+ # It's a macro, not a constructor if there is no type in the first param
+ - match: '({{identifier}})\s*(\()(?=\s*(?!void){{identifier}}\s*[),])'
+ captures:
+ 1: variable.function.c++
+ 2: meta.group.c++ punctuation.section.group.begin.c++
+ push:
+ - meta_scope: meta.function-call.c++
+ - meta_content_scope: meta.group.c++
+ - match: '\)'
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ # Constructor
+ - include: preprocessor-workaround-eat-macro-before-identifier
+ - match: '((?!{{before_tag}}|template){{identifier}})(?=\s*\()'
+ scope: meta.method.constructor.c++ entity.name.function.constructor.c++
+ set: method-definition-params
+ # Long form constructor
+ - match: '({{identifier}}\s*(::)\s*{{identifier}})(?=\s*\()'
+ captures:
+ 1: meta.method.constructor.c++ entity.name.function.constructor.c++
+ 2: punctuation.accessor.c++
+ push: method-definition-params
+ - match: '(?=\S)'
+ set: data-structures-type
+
+ data-structures-type:
+ - include: comments
+ - match: \*|&
+ scope: keyword.operator.c++
+ # Cast methods
+ - match: '(operator)\s+({{identifier}})(?=\s*(\(|$))'
+ captures:
+ 1: keyword.control.c++
+ 2: meta.method.c++ entity.name.function.c++
+ set: method-definition-params
+ - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}}|operator)\b)'
+ pop: true
+ - match: '(?=\s)'
+ set: data-structures-maybe-method
+ # If a class/struct/enum followed by a name that is not a macro or declspec
+ # then this is likely a return type of a function. This is uncommon.
+ - match: |-
+ (?x:
+ ({{before_tag}})
+ \s+
+ (?=
+ (?![[:upper:][:digit:]_]+\b|__declspec|{{before_tag}})
+ {{path_lookahead}}
+ (\s+{{identifier}}\s*\(|\s*[*&])
+ )
+ )
+ captures:
+ 1: storage.type.c++
+ set:
+ - include: identifiers
+ - match: ''
+ set: data-structures-maybe-method
+ # The previous match handles return types of struct/enum/etc from a func,
+ # there this one exits the context to allow matching an actual struct/class
+ - match: '(?=\b({{before_tag}})\b)'
+ set: data-structures
+ - match: '(?=\b({{casts}})\b\s*<)'
+ pop: true
+ - match: '{{non_angle_brackets}}'
+ pop: true
+ - include: angle-brackets
+ - include: types
+ - include: variables
+ - include: constants
+ - include: identifiers
+ - match: (?=[&*])
+ set: data-structures-maybe-method
+ - match: (?=\W)
+ pop: true
+
+ data-structures-maybe-method:
+ - include: comments
+ # Consume pointer info, macros and any type info that was offset by macros
+ - match: \*|&
+ scope: keyword.operator.c++
+ - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}})\b)'
+ pop: true
+ - match: '\b({{type_qualifier}})\b'
+ scope: storage.modifier.c++
+ - match: '{{non_angle_brackets}}'
+ pop: true
+ - include: angle-brackets
+ - include: types
+ - include: modifiers-parens
+ - include: modifiers
+ # Operator overloading
+ - match: '{{operator_method_name}}(?=\s*(\(|$))'
+ scope: meta.method.c++ entity.name.function.c++
+ set: method-definition-params
+ # Identifier that is not the function name - likely a macro or type
+ - match: '(?={{path_lookahead}}([ \t]+|[*&])(?!\s*(<|::|\()))'
+ push:
+ - include: identifiers
+ - match: ''
+ pop: true
+ # Real function definition
+ - match: '(?={{path_lookahead}}({{generic_lookahead}})\s*(\())'
+ set: [method-definition-params, data-structures-function-identifier-generic]
+ - match: '(?={{path_lookahead}}\s*(\())'
+ set: [method-definition-params, data-structures-function-identifier]
+ - match: '(?={{path_lookahead}}\s*::\s*$)'
+ set: [method-definition-params, data-structures-function-identifier]
+ - match: '(?=\S)'
+ pop: true
+
+ data-structures-function-identifier-generic:
+ - include: angle-brackets
+ - match: '(?={{identifier}})'
+ push:
+ - meta_content_scope: entity.name.function.c++
+ - include: identifiers
+ - match: '(?=<)'
+ pop: true
+ - match: '(?=\()'
+ pop: true
+
+ data-structures-function-identifier:
+ - meta_content_scope: entity.name.function.c++
+ - include: identifiers
+ - match: '(?=\S)'
+ pop: true
+
+ method-definition-params:
+ - meta_content_scope: meta.method.c++
+ - include: comments
+ - match: '(?=\()'
+ set:
+ - match: \(
+ scope: meta.method.parameters.c++ meta.group.c++ punctuation.section.group.begin.c++
+ set:
+ - meta_content_scope: meta.method.parameters.c++ meta.group.c++
+ - match : \)
+ scope: punctuation.section.group.end.c++
+ set: method-definition-continue
+ - match: '\bvoid\b'
+ scope: storage.type.c++
+ - match: '{{identifier}}(?=\s*(\[|,|\)|=))'
+ scope: variable.parameter.c++
+ - match: '='
+ scope: keyword.operator.assignment.c++
+ push:
+ - match: '(?=,|\))'
+ pop: true
+ - include: expressions-minus-generic-type
+ - include: expressions-minus-generic-type
+ - match: '(?=\S)'
+ pop: true
+
+ method-definition-continue:
+ - meta_content_scope: meta.method.c++
+ - include: comments
+ - match: '(?=;)'
+ pop: true
+ - match: '->'
+ scope: punctuation.separator.c++
+ set: method-definition-trailing-return
+ - include: function-specifiers
+ - match: '='
+ scope: keyword.operator.assignment.c++
+ - match: '&'
+ scope: keyword.operator.c++
+ - match: \b0\b
+ scope: constant.numeric.c++
+ - match: \b(default|delete)\b
+ scope: storage.modifier.c++
+ - match: '(?=:)'
+ set:
+ - match: ':'
+ scope: punctuation.separator.initializer-list.c++
+ set:
+ - meta_scope: meta.method.constructor.initializer-list.c++
+ - match: '{{identifier}}'
+ scope: variable.other.readwrite.member.c++
+ push:
+ - match: \(
+ scope: meta.group.c++ punctuation.section.group.begin.c++
+ set:
+ - meta_content_scope: meta.group.c++
+ - match: \)
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ - match: \{
+ scope: meta.group.c++ punctuation.section.group.begin.c++
+ set:
+ - meta_content_scope: meta.group.c++
+ - match: \}
+ scope: meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+ - include: comments
+ - match: (?=\{|;)
+ set: method-definition-continue
+ - include: expressions
+ - match: '(?=\{)'
+ set: method-definition-body
+ - match: '(?=\S)'
+ pop: true
+
+ method-definition-trailing-return:
+ - include: comments
+ - match: '(?=;)'
+ pop: true
+ - match: '(?=\{)'
+ set: method-definition-body
+ - include: function-specifiers
+ - include: function-trailing-return-type
+
+ method-definition-body:
+ - meta_content_scope: meta.method.c++ meta.block.c++
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ set:
+ - meta_content_scope: meta.method.c++ meta.block.c++
+ - match: '\}'
+ scope: meta.method.c++ meta.block.c++ punctuation.section.block.end.c++
+ pop: true
+ - match: (?=^\s*#\s*(elif|else|endif)\b)
+ pop: true
+ - match: '(?=({{before_tag}})([^(;]+$|.*\{))'
+ push: data-structures
+ - include: statements
+
+ ## Preprocessor for data-structures
+
+ preprocessor-data-structures:
+ - include: preprocessor-rule-enabled-data-structures
+ - include: preprocessor-rule-disabled-data-structures
+ - include: preprocessor-practical-workarounds
+
+ preprocessor-rule-disabled-data-structures:
+ - match: ^\s*((#if)\s+(0))\b
+ captures:
+ 1: meta.preprocessor.c++
+ 2: keyword.control.import.c++
+ 3: constant.numeric.preprocessor.c++
+ push:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: ^\s*(#\s*else)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.else.c++
+ push:
+ - match: (?=^\s*#\s*endif\b)
+ pop: true
+ - include: negated-block
+ - include: data-structures-body
+ - match: ""
+ push:
+ - meta_scope: comment.block.preprocessor.if-branch.c++
+ - match: (?=^\s*#\s*(else|endif)\b)
+ pop: true
+ - include: scope:source.c#preprocessor-disabled
+
+ preprocessor-rule-enabled-data-structures:
+ - match: ^\s*((#if)\s+(0*1))\b
+ captures:
+ 1: meta.preprocessor.c++
+ 2: keyword.control.import.c++
+ 3: constant.numeric.preprocessor.c++
+ push:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: ^\s*(#\s*else)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.else.c++
+ push:
+ - meta_content_scope: comment.block.preprocessor.else-branch.c++
+ - match: (?=^\s*#\s*endif\b)
+ pop: true
+ - include: scope:source.c#preprocessor-disabled
+ - match: ""
+ push:
+ - match: (?=^\s*#\s*(else|endif)\b)
+ pop: true
+ - include: negated-block
+ - include: data-structures-body
+
+ ## Preprocessor for global
+
+ preprocessor-global:
+ - include: preprocessor-rule-enabled-global
+ - include: preprocessor-rule-disabled-global
+ - include: preprocessor-rule-other-global
+
+ preprocessor-statements:
+ - include: preprocessor-rule-enabled-statements
+ - include: preprocessor-rule-disabled-statements
+ - include: preprocessor-rule-other-statements
+
+ preprocessor-expressions:
+ - include: scope:source.c#incomplete-inc
+ - include: preprocessor-macro-define
+ - include: scope:source.c#pragma-mark
+ - include: preprocessor-other
+
+ preprocessor-rule-disabled-global:
+ - match: ^\s*((#if)\s+(0))\b
+ captures:
+ 1: meta.preprocessor.c++
+ 2: keyword.control.import.c++
+ 3: constant.numeric.preprocessor.c++
+ push:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: ^\s*(#\s*else)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.else.c++
+ push:
+ - match: (?=^\s*#\s*endif\b)
+ pop: true
+ - include: preprocessor-global
+ - include: negated-block
+ - include: global
+ - match: ""
+ push:
+ - meta_scope: comment.block.preprocessor.if-branch.c++
+ - match: (?=^\s*#\s*(else|endif)\b)
+ pop: true
+ - include: scope:source.c#preprocessor-disabled
+
+ preprocessor-rule-enabled-global:
+ - match: ^\s*((#if)\s+(0*1))\b
+ captures:
+ 1: meta.preprocessor.c++
+ 2: keyword.control.import.c++
+ 3: constant.numeric.preprocessor.c++
+ push:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: ^\s*(#\s*else)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.else.c++
+ push:
+ - meta_content_scope: comment.block.preprocessor.else-branch.c++
+ - match: (?=^\s*#\s*endif\b)
+ pop: true
+ - include: scope:source.c#preprocessor-disabled
+ - match: ""
+ push:
+ - match: (?=^\s*#\s*(else|endif)\b)
+ pop: true
+ - include: preprocessor-global
+ - include: negated-block
+ - include: global
+
+ preprocessor-rule-other-global:
+ - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b
+ captures:
+ 1: keyword.control.import.c++
+ push:
+ - meta_scope: meta.preprocessor.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-comments
+ - match: \bdefined\b
+ scope: keyword.control.c++
+ # Enter a new scope where all elif/else branches have their
+ # contexts popped by a subsequent elif/else/endif. This ensures that
+ # preprocessor branches don't push multiple meta.block scopes on
+ # the stack, thus messing up the "global" context's detection of
+ # functions.
+ - match: $\n
+ set: preprocessor-if-branch-global
+
+ # These gymnastics here ensure that we are properly handling scope even
+ # when the preprocessor is used to create different scope beginnings, such
+ # as a different if/while condition
+ preprocessor-if-branch-global:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: (?=^\s*#\s*(elif|else)\b)
+ push: preprocessor-elif-else-branch-global
+ - match: \{
+ scope: punctuation.section.block.begin.c++
+ set: preprocessor-block-if-branch-global
+ - include: preprocessor-global
+ - include: negated-block
+ - include: global
+
+ preprocessor-block-if-branch-global:
+ - meta_scope: meta.block.c++
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ set: preprocessor-block-finish-global
+ - match: (?=^\s*#\s*(elif|else)\b)
+ push: preprocessor-elif-else-branch-global
+ - match: \}
+ scope: punctuation.section.block.end.c++
+ set: preprocessor-if-branch-global
+ - include: statements
+
+ preprocessor-block-finish-global:
+ - meta_scope: meta.block.c++
+ - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ set: preprocessor-block-finish-if-branch-global
+ - match: \}
+ scope: punctuation.section.block.end.c++
+ pop: true
+ - include: statements
+
+ preprocessor-block-finish-if-branch-global:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: keyword.control.import.c++
+ pop: true
+ - match: \}
+ scope: punctuation.section.block.end.c++
+ set: preprocessor-if-branch-global
+ - include: statements
+
+ preprocessor-elif-else-branch-global:
+ - match: (?=^\s*#\s*(endif)\b)
+ pop: true
+ - include: preprocessor-global
+ - include: negated-block
+ - include: global
+
+ ## Preprocessor for statements
+
+ preprocessor-rule-disabled-statements:
+ - match: ^\s*((#if)\s+(0))\b
+ captures:
+ 1: meta.preprocessor.c++
+ 2: keyword.control.import.c++
+ 3: constant.numeric.preprocessor.c++
+ push:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: ^\s*(#\s*else)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.else.c++
+ push:
+ - match: (?=^\s*#\s*endif\b)
+ pop: true
+ - include: negated-block
+ - include: statements
+ - match: ""
+ push:
+ - meta_scope: comment.block.preprocessor.if-branch.c++
+ - match: (?=^\s*#\s*(else|endif)\b)
+ pop: true
+ - include: scope:source.c#preprocessor-disabled
+
+ preprocessor-rule-enabled-statements:
+ - match: ^\s*((#if)\s+(0*1))\b
+ captures:
+ 1: meta.preprocessor.c++
+ 2: keyword.control.import.c++
+ 3: constant.numeric.preprocessor.c++
+ push:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: ^\s*(#\s*else)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.else.c++
+ push:
+ - meta_content_scope: comment.block.preprocessor.else-branch.c++
+ - match: (?=^\s*#\s*endif\b)
+ pop: true
+ - include: scope:source.c#preprocessor-disabled
+ - match: ""
+ push:
+ - match: (?=^\s*#\s*(else|endif)\b)
+ pop: true
+ - include: negated-block
+ - include: statements
+
+ preprocessor-rule-other-statements:
+ - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b
+ captures:
+ 1: keyword.control.import.c++
+ push:
+ - meta_scope: meta.preprocessor.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-comments
+ - match: \bdefined\b
+ scope: keyword.control.c++
+ # Enter a new scope where all elif/else branches have their
+ # contexts popped by a subsequent elif/else/endif. This ensures that
+ # preprocessor branches don't push multiple meta.block scopes on
+ # the stack, thus messing up the "global" context's detection of
+ # functions.
+ - match: $\n
+ set: preprocessor-if-branch-statements
+
+ # These gymnastics here ensure that we are properly handling scope even
+ # when the preprocessor is used to create different scope beginnings, such
+ # as a different if/while condition
+ preprocessor-if-branch-statements:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ pop: true
+ - match: (?=^\s*#\s*(elif|else)\b)
+ push: preprocessor-elif-else-branch-statements
+ - match: \{
+ scope: punctuation.section.block.begin.c++
+ set: preprocessor-block-if-branch-statements
+ - match: (?=(?!{{non_func_keywords}}){{path_lookahead}}\s*\()
+ set: preprocessor-if-branch-function-call
+ - include: negated-block
+ - include: statements
+
+ preprocessor-if-branch-function-call:
+ - meta_content_scope: meta.function-call.c++
+ - include: scope:source.c#c99
+ - match: '(?:(::)\s*)?{{identifier}}\s*(::)\s*'
+ scope: variable.function.c++
+ captures:
+ 1: punctuation.accessor.c++
+ 2: punctuation.accessor.c++
+ - match: '(?:(::)\s*)?{{identifier}}'
+ scope: variable.function.c++
+ captures:
+ 1: punctuation.accessor.c++
+ - match: '\('
+ scope: meta.group.c++ punctuation.section.group.begin.c++
+ set: preprocessor-if-branch-function-call-arguments
+
+ preprocessor-if-branch-function-call-arguments:
+ - meta_content_scope: meta.function-call.c++ meta.group.c++
+ - match : \)
+ scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++
+ set: preprocessor-if-branch-statements
+ - match: ^\s*(#\s*(?:elif|else))\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ set: preprocessor-if-branch-statements
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ set: preprocessor-if-branch-function-call-arguments-finish
+ - include: expressions
+
+ preprocessor-if-branch-function-call-arguments-finish:
+ - meta_content_scope: meta.function-call.c++ meta.group.c++
+ - match: \)
+ scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++
+ pop: true
+ - include: expressions
+
+ preprocessor-block-if-branch-statements:
+ - meta_scope: meta.block.c++
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ set: preprocessor-block-finish-statements
+ - match: (?=^\s*#\s*(elif|else)\b)
+ push: preprocessor-elif-else-branch-statements
+ - match: \}
+ scope: punctuation.section.block.end.c++
+ set: preprocessor-if-branch-statements
+ - include: statements
+
+ preprocessor-block-finish-statements:
+ - meta_scope: meta.block.c++
+ - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ set: preprocessor-block-finish-if-branch-statements
+ - match: \}
+ scope: punctuation.section.block.end.c++
+ pop: true
+ - include: statements
+
+ preprocessor-block-finish-if-branch-statements:
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: keyword.control.import.c++
+ pop: true
+ - match: \}
+ scope: meta.block.c++ punctuation.section.block.end.c++
+ set: preprocessor-if-branch-statements
+ - include: statements
+
+ preprocessor-elif-else-branch-statements:
+ - match: (?=^\s*#\s*endif\b)
+ pop: true
+ - include: negated-block
+ - include: statements
+
+ ## Preprocessor other
+
+ negated-block:
+ - match: '\}'
+ scope: punctuation.section.block.end.c++
+ push:
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ pop: true
+ - match: (?=^\s*#\s*(elif|else|endif)\b)
+ pop: true
+ - include: statements
+
+ preprocessor-macro-define:
+ - match: ^\s*(\#\s*define)\b
+ captures:
+ 1: meta.preprocessor.macro.c++ keyword.control.import.define.c++
+ push:
+ - meta_content_scope: meta.preprocessor.macro.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-line-ending
+ - include: scope:source.c#preprocessor-comments
+ - match: '({{identifier}})(?=\()'
+ scope: entity.name.function.preprocessor.c++
+ set:
+ - match: '\('
+ scope: punctuation.section.group.begin.c++
+ set: preprocessor-macro-params
+ - match: '{{identifier}}'
+ scope: entity.name.constant.preprocessor.c++
+ set: preprocessor-macro-definition
+
+ preprocessor-macro-params:
+ - meta_scope: meta.preprocessor.macro.parameters.c++ meta.group.c++
+ - match: '{{identifier}}'
+ scope: variable.parameter.c++
+ - match: \)
+ scope: punctuation.section.group.end.c++
+ set: preprocessor-macro-definition
+ - match: ','
+ scope: punctuation.separator.c++
+ push:
+ - match: '{{identifier}}'
+ scope: variable.parameter.c++
+ pop: true
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-comments
+ - match: '\.\.\.'
+ scope: keyword.operator.variadic.c++
+ - match: '(?=\))'
+ pop: true
+ - match: (/\*).*(\*/)
+ scope: comment.block.c++
+ captures:
+ 1: punctuation.definition.comment.c++
+ 2: punctuation.definition.comment.c++
+ - match: '\S+'
+ scope: invalid.illegal.unexpected-character.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-comments
+ - match: '\.\.\.'
+ scope: keyword.operator.variadic.c++
+ - match: (/\*).*(\*/)
+ scope: comment.block.c++
+ captures:
+ 1: punctuation.definition.comment.c++
+ 2: punctuation.definition.comment.c++
+ - match: $\n
+ scope: invalid.illegal.unexpected-end-of-line.c++
+
+ preprocessor-macro-definition:
+ - meta_content_scope: meta.preprocessor.macro.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-line-ending
+ - include: scope:source.c#preprocessor-comments
+ # Don't define blocks in define statements
+ - match: '\{'
+ scope: punctuation.section.block.begin.c++
+ - match: '\}'
+ scope: punctuation.section.block.end.c++
+ - include: expressions
+
+ preprocessor-practical-workarounds:
+ - include: preprocessor-convention-ignore-uppercase-ident-lines
+ - include: scope:source.c#preprocessor-convention-ignore-uppercase-calls-without-semicolon
+
+ preprocessor-convention-ignore-uppercase-ident-lines:
+ - match: ^(\s*{{macro_identifier}})+\s*$
+ scope: meta.assumed-macro.c++
+ push:
+ # It's possible that we are dealing with a function return type on its own line, and the
+ # name of the function is on the subsequent line.
+ - match: '(?={{path_lookahead}}({{generic_lookahead}}({{path_lookahead}})?)\s*\()'
+ set: [function-definition-params, global-function-identifier-generic]
+ - match: '(?={{path_lookahead}}\s*\()'
+ set: [function-definition-params, global-function-identifier]
+ - match: ^
+ pop: true
+
+ preprocessor-other:
+ - match: ^\s*(#\s*(?:if|ifdef|ifndef|elif|else|line|pragma|undef))\b
+ captures:
+ 1: keyword.control.import.c++
+ push:
+ - meta_scope: meta.preprocessor.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-line-ending
+ - include: scope:source.c#preprocessor-comments
+ - match: \bdefined\b
+ scope: keyword.control.c++
+ - match: ^\s*(#\s*endif)\b
+ captures:
+ 1: meta.preprocessor.c++ keyword.control.import.c++
+ - match: ^\s*(#\s*(?:error|warning))\b
+ captures:
+ 1: keyword.control.import.error.c++
+ push:
+ - meta_scope: meta.preprocessor.diagnostic.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-line-ending
+ - include: scope:source.c#preprocessor-comments
+ - include: strings
+ - match: '\S+'
+ scope: string.unquoted.c++
+ - match: ^\s*(#\s*(?:include|include_next|import))\b
+ captures:
+ 1: keyword.control.import.include.c++
+ push:
+ - meta_scope: meta.preprocessor.include.c++
+ - include: scope:source.c#preprocessor-line-continuation
+ - include: scope:source.c#preprocessor-line-ending
+ - include: scope:source.c#preprocessor-comments
+ - match: '"'
+ scope: punctuation.definition.string.begin.c++
+ push:
+ - meta_scope: string.quoted.double.include.c++
+ - match: '"'
+ scope: punctuation.definition.string.end.c++
+ pop: true
+ - match: <
+ scope: punctuation.definition.string.begin.c++
+ push:
+ - meta_scope: string.quoted.other.lt-gt.include.c++
+ - match: '>'
+ scope: punctuation.definition.string.end.c++
+ pop: true
+ - include: preprocessor-practical-workarounds
diff --git a/thirdparty/fmt/support/README b/thirdparty/fmt/support/README
new file mode 100644
index 000000000..468f5485d
--- /dev/null
+++ b/thirdparty/fmt/support/README
@@ -0,0 +1,4 @@
+This directory contains build support files such as
+
+* CMake modules
+* Build scripts
diff --git a/thirdparty/fmt/support/Vagrantfile b/thirdparty/fmt/support/Vagrantfile
new file mode 100644
index 000000000..9d0ff6a53
--- /dev/null
+++ b/thirdparty/fmt/support/Vagrantfile
@@ -0,0 +1,19 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# A vagrant config for testing against gcc-4.8.
+Vagrant.configure("2") do |config|
+ config.vm.box = "bento/ubuntu-22.04-arm64"
+
+ config.vm.provider "vmware_desktop" do |vb|
+ vb.memory = "4096"
+ end
+
+ config.vm.provision "shell", inline: <<-SHELL
+ apt-get update
+ apt-get install -y g++ make wget git
+ wget -q https://github.com/Kitware/CMake/releases/download/v3.26.0/cmake-3.26.0-Linux-x86_64.tar.gz
+ tar xzf cmake-3.26.0-Linux-x86_64.tar.gz
+ ln -s `pwd`/cmake-3.26.0-Linux-x86_64/bin/cmake /usr/local/bin
+ SHELL
+end
diff --git a/thirdparty/fmt/support/build.gradle b/thirdparty/fmt/support/build.gradle
new file mode 100644
index 000000000..c5126d058
--- /dev/null
+++ b/thirdparty/fmt/support/build.gradle
@@ -0,0 +1,132 @@
+import java.nio.file.Paths
+
+// General gradle arguments for root project
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ //
+ // https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
+ //
+ // Notice that 4.0.0 here is the version of [Android Gradle Plugin]
+ // According to URL above you will need Gradle 6.1 or higher
+ //
+ classpath "com.android.tools.build:gradle:4.1.1"
+ }
+}
+repositories {
+ google()
+ jcenter()
+}
+
+// Project's root where CMakeLists.txt exists: rootDir/support/.cxx -> rootDir
+def rootDir = Paths.get(project.buildDir.getParent()).getParent()
+println("rootDir: ${rootDir}")
+
+// Output: Shared library (.so) for Android
+apply plugin: "com.android.library"
+android {
+ compileSdkVersion 25 // Android 7.0
+
+ // Target ABI
+ // - This option controls target platform of module
+ // - The platform might be limited by compiler's support
+ // some can work with Clang(default), but some can work only with GCC...
+ // if bad, both toolchains might not support it
+ splits {
+ abi {
+ enable true
+ // Specify platforms for Application
+ reset()
+ include "arm64-v8a", "armeabi-v7a", "x86_64"
+ }
+ }
+ ndkVersion "21.3.6528147" // ANDROID_NDK_HOME is deprecated. Be explicit
+
+ defaultConfig {
+ minSdkVersion 21 // Android 5.0+
+ targetSdkVersion 25 // Follow Compile SDK
+ versionCode 34 // Follow release count
+ versionName "7.1.2" // Follow Official version
+
+ externalNativeBuild {
+ cmake {
+ arguments "-DANDROID_STL=c++_shared" // Specify Android STL
+ arguments "-DBUILD_SHARED_LIBS=true" // Build shared object
+ arguments "-DFMT_TEST=false" // Skip test
+ arguments "-DFMT_DOC=false" // Skip document
+ cppFlags "-std=c++17"
+ targets "fmt"
+ }
+ }
+ println(externalNativeBuild.cmake.cppFlags)
+ println(externalNativeBuild.cmake.arguments)
+ }
+
+ // External Native build
+ // - Use existing CMakeList.txt
+ // - Give path to CMake. This gradle file should be
+ // neighbor of the top level cmake
+ externalNativeBuild {
+ cmake {
+ version "3.10.0+"
+ path "${rootDir}/CMakeLists.txt"
+ // buildStagingDirectory "./build" // Custom path for cmake output
+ }
+ }
+
+ sourceSets{
+ // Android Manifest for Gradle
+ main {
+ manifest.srcFile "AndroidManifest.xml"
+ }
+ }
+
+ // https://developer.android.com/studio/build/native-dependencies#build_system_configuration
+ buildFeatures {
+ prefab true
+ prefabPublishing true
+ }
+ prefab {
+ fmt {
+ headers "${rootDir}/include"
+ }
+ }
+}
+
+assemble.doLast
+{
+ // Instead of `ninja install`, Gradle will deploy the files.
+ // We are doing this since FMT is dependent to the ANDROID_STL after build
+ copy {
+ from "build/intermediates/cmake"
+ into "${rootDir}/libs"
+ }
+ // Copy debug binaries
+ copy {
+ from "${rootDir}/libs/debug/obj"
+ into "${rootDir}/libs/debug"
+ }
+ // Copy Release binaries
+ copy {
+ from "${rootDir}/libs/release/obj"
+ into "${rootDir}/libs/release"
+ }
+ // Remove empty directory
+ delete "${rootDir}/libs/debug/obj"
+ delete "${rootDir}/libs/release/obj"
+
+ // Copy AAR files. Notice that the aar is named after the folder of this script.
+ copy {
+ from "build/outputs/aar/support-release.aar"
+ into "${rootDir}/libs"
+ rename "support-release.aar", "fmt-release.aar"
+ }
+ copy {
+ from "build/outputs/aar/support-debug.aar"
+ into "${rootDir}/libs"
+ rename "support-debug.aar", "fmt-debug.aar"
+ }
+}
diff --git a/thirdparty/fmt/support/check-commits b/thirdparty/fmt/support/check-commits
new file mode 100755
index 000000000..11472d41f
--- /dev/null
+++ b/thirdparty/fmt/support/check-commits
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+"""Compile source on a range of commits
+
+Usage:
+ check-commits <start> <source>
+"""
+
+import docopt, os, sys, tempfile
+from subprocess import check_call, check_output, run
+
+args = docopt.docopt(__doc__)
+start = args.get('<start>')
+source = args.get('<source>')
+
+cwd = os.getcwd()
+
+with tempfile.TemporaryDirectory() as work_dir:
+ check_call(['git', 'clone', 'https://github.com/fmtlib/fmt.git'],
+ cwd=work_dir)
+ repo_dir = os.path.join(work_dir, 'fmt')
+ commits = check_output(
+ ['git', 'rev-list', f'{start}..HEAD', '--abbrev-commit',
+ '--', 'include', 'src'],
+ text=True, cwd=repo_dir).rstrip().split('\n')
+ commits.reverse()
+ print('Time\tCommit')
+ for commit in commits:
+ check_call(['git', '-c', 'advice.detachedHead=false', 'checkout', commit],
+ cwd=repo_dir)
+ returncode = run(
+ ['c++', '-std=c++11', '-O3', '-DNDEBUG', '-I', 'include',
+ 'src/format.cc', os.path.join(cwd, source)], cwd=repo_dir).returncode
+ if returncode != 0:
+ continue
+ times = []
+ for i in range(5):
+ output = check_output([os.path.join(repo_dir, 'a.out')], text=True)
+ times.append(float(output))
+ message = check_output(['git', 'log', '-1', '--pretty=format:%s', commit],
+ cwd=repo_dir, text=True)
+ print(f'{min(times)}\t{commit} {message[:40]}')
+ sys.stdout.flush()
diff --git a/thirdparty/fmt/support/cmake/FindSetEnv.cmake b/thirdparty/fmt/support/cmake/FindSetEnv.cmake
new file mode 100644
index 000000000..4e2da5408
--- /dev/null
+++ b/thirdparty/fmt/support/cmake/FindSetEnv.cmake
@@ -0,0 +1,7 @@
+# A CMake script to find SetEnv.cmd.
+
+find_program(WINSDK_SETENV NAMES SetEnv.cmd
+ PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]/bin")
+if (WINSDK_SETENV AND PRINT_PATH)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${WINSDK_SETENV}")
+endif ()
diff --git a/thirdparty/fmt/support/cmake/JoinPaths.cmake b/thirdparty/fmt/support/cmake/JoinPaths.cmake
new file mode 100644
index 000000000..32d6d6685
--- /dev/null
+++ b/thirdparty/fmt/support/cmake/JoinPaths.cmake
@@ -0,0 +1,26 @@
+# This module provides function for joining paths
+# known from from most languages
+#
+# Original license:
+# SPDX-License-Identifier: (MIT OR CC0-1.0)
+# Explicit permission given to distribute this module under
+# the terms of the project as described in /LICENSE.rst.
+# Copyright 2020 Jan Tojnar
+# https://github.com/jtojnar/cmake-snips
+#
+# Modelled after Python’s os.path.join
+# https://docs.python.org/3.7/library/os.path.html#os.path.join
+# Windows not supported
+function(join_paths joined_path first_path_segment)
+ set(temp_path "${first_path_segment}")
+ foreach(current_segment IN LISTS ARGN)
+ if(NOT ("${current_segment}" STREQUAL ""))
+ if(IS_ABSOLUTE "${current_segment}")
+ set(temp_path "${current_segment}")
+ else()
+ set(temp_path "${temp_path}/${current_segment}")
+ endif()
+ endif()
+ endforeach()
+ set(${joined_path} "${temp_path}" PARENT_SCOPE)
+endfunction()
diff --git a/thirdparty/fmt/support/cmake/fmt-config.cmake.in b/thirdparty/fmt/support/cmake/fmt-config.cmake.in
new file mode 100644
index 000000000..bc1684f24
--- /dev/null
+++ b/thirdparty/fmt/support/cmake/fmt-config.cmake.in
@@ -0,0 +1,7 @@
+@PACKAGE_INIT@
+
+if (NOT TARGET fmt::fmt)
+ include(${CMAKE_CURRENT_LIST_DIR}/@[email protected])
+endif ()
+
+check_required_components(fmt)
diff --git a/thirdparty/fmt/support/cmake/fmt.pc.in b/thirdparty/fmt/support/cmake/fmt.pc.in
new file mode 100644
index 000000000..29976a8af
--- /dev/null
+++ b/thirdparty/fmt/support/cmake/fmt.pc.in
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@libdir_for_pc_file@
+includedir=@includedir_for_pc_file@
+
+Name: fmt
+Description: A modern formatting library
+Version: @FMT_VERSION@
+Libs: -L${libdir} -l@FMT_LIB_NAME@
+Cflags: -I${includedir}
+
diff --git a/thirdparty/fmt/support/docopt.py b/thirdparty/fmt/support/docopt.py
new file mode 100644
index 000000000..2e43f7cef
--- /dev/null
+++ b/thirdparty/fmt/support/docopt.py
@@ -0,0 +1,581 @@
+"""Pythonic command-line interface parser that will make you smile.
+
+ * http://docopt.org
+ * Repository and issue-tracker: https://github.com/docopt/docopt
+ * Licensed under terms of MIT license (see LICENSE-MIT)
+ * Copyright (c) 2013 Vladimir Keleshev, [email protected]
+
+"""
+import sys
+import re
+
+
+__all__ = ['docopt']
+__version__ = '0.6.1'
+
+
+class DocoptLanguageError(Exception):
+
+ """Error in construction of usage-message by developer."""
+
+
+class DocoptExit(SystemExit):
+
+ """Exit in case user invoked program with incorrect arguments."""
+
+ usage = ''
+
+ def __init__(self, message=''):
+ SystemExit.__init__(self, (message + '\n' + self.usage).strip())
+
+
+class Pattern(object):
+
+ def __eq__(self, other):
+ return repr(self) == repr(other)
+
+ def __hash__(self):
+ return hash(repr(self))
+
+ def fix(self):
+ self.fix_identities()
+ self.fix_repeating_arguments()
+ return self
+
+ def fix_identities(self, uniq=None):
+ """Make pattern-tree tips point to same object if they are equal."""
+ if not hasattr(self, 'children'):
+ return self
+ uniq = list(set(self.flat())) if uniq is None else uniq
+ for i, child in enumerate(self.children):
+ if not hasattr(child, 'children'):
+ assert child in uniq
+ self.children[i] = uniq[uniq.index(child)]
+ else:
+ child.fix_identities(uniq)
+
+ def fix_repeating_arguments(self):
+ """Fix elements that should accumulate/increment values."""
+ either = [list(child.children) for child in transform(self).children]
+ for case in either:
+ for e in [child for child in case if case.count(child) > 1]:
+ if type(e) is Argument or type(e) is Option and e.argcount:
+ if e.value is None:
+ e.value = []
+ elif type(e.value) is not list:
+ e.value = e.value.split()
+ if type(e) is Command or type(e) is Option and e.argcount == 0:
+ e.value = 0
+ return self
+
+
+def transform(pattern):
+ """Expand pattern into an (almost) equivalent one, but with single Either.
+
+ Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
+ Quirks: [-a] => (-a), (-a...) => (-a -a)
+
+ """
+ result = []
+ groups = [[pattern]]
+ while groups:
+ children = groups.pop(0)
+ parents = [Required, Optional, OptionsShortcut, Either, OneOrMore]
+ if any(t in map(type, children) for t in parents):
+ child = [c for c in children if type(c) in parents][0]
+ children.remove(child)
+ if type(child) is Either:
+ for c in child.children:
+ groups.append([c] + children)
+ elif type(child) is OneOrMore:
+ groups.append(child.children * 2 + children)
+ else:
+ groups.append(child.children + children)
+ else:
+ result.append(children)
+ return Either(*[Required(*e) for e in result])
+
+
+class LeafPattern(Pattern):
+
+ """Leaf/terminal node of a pattern tree."""
+
+ def __init__(self, name, value=None):
+ self.name, self.value = name, value
+
+ def __repr__(self):
+ return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
+
+ def flat(self, *types):
+ return [self] if not types or type(self) in types else []
+
+ def match(self, left, collected=None):
+ collected = [] if collected is None else collected
+ pos, match = self.single_match(left)
+ if match is None:
+ return False, left, collected
+ left_ = left[:pos] + left[pos + 1:]
+ same_name = [a for a in collected if a.name == self.name]
+ if type(self.value) in (int, list):
+ if type(self.value) is int:
+ increment = 1
+ else:
+ increment = ([match.value] if type(match.value) is str
+ else match.value)
+ if not same_name:
+ match.value = increment
+ return True, left_, collected + [match]
+ same_name[0].value += increment
+ return True, left_, collected
+ return True, left_, collected + [match]
+
+
+class BranchPattern(Pattern):
+
+ """Branch/inner node of a pattern tree."""
+
+ def __init__(self, *children):
+ self.children = list(children)
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__,
+ ', '.join(repr(a) for a in self.children))
+
+ def flat(self, *types):
+ if type(self) in types:
+ return [self]
+ return sum([child.flat(*types) for child in self.children], [])
+
+
+class Argument(LeafPattern):
+
+ def single_match(self, left):
+ for n, pattern in enumerate(left):
+ if type(pattern) is Argument:
+ return n, Argument(self.name, pattern.value)
+ return None, None
+
+ @classmethod
+ def parse(class_, source):
+ name = re.findall('(<\S*?>)', source)[0]
+ value = re.findall('\[default: (.*)\]', source, flags=re.I)
+ return class_(name, value[0] if value else None)
+
+
+class Command(Argument):
+
+ def __init__(self, name, value=False):
+ self.name, self.value = name, value
+
+ def single_match(self, left):
+ for n, pattern in enumerate(left):
+ if type(pattern) is Argument:
+ if pattern.value == self.name:
+ return n, Command(self.name, True)
+ else:
+ break
+ return None, None
+
+
+class Option(LeafPattern):
+
+ def __init__(self, short=None, long=None, argcount=0, value=False):
+ assert argcount in (0, 1)
+ self.short, self.long, self.argcount = short, long, argcount
+ self.value = None if value is False and argcount else value
+
+ @classmethod
+ def parse(class_, option_description):
+ short, long, argcount, value = None, None, 0, False
+ options, _, description = option_description.strip().partition(' ')
+ options = options.replace(',', ' ').replace('=', ' ')
+ for s in options.split():
+ if s.startswith('--'):
+ long = s
+ elif s.startswith('-'):
+ short = s
+ else:
+ argcount = 1
+ if argcount:
+ matched = re.findall('\[default: (.*)\]', description, flags=re.I)
+ value = matched[0] if matched else None
+ return class_(short, long, argcount, value)
+
+ def single_match(self, left):
+ for n, pattern in enumerate(left):
+ if self.name == pattern.name:
+ return n, pattern
+ return None, None
+
+ @property
+ def name(self):
+ return self.long or self.short
+
+ def __repr__(self):
+ return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
+ self.argcount, self.value)
+
+
+class Required(BranchPattern):
+
+ def match(self, left, collected=None):
+ collected = [] if collected is None else collected
+ l = left
+ c = collected
+ for pattern in self.children:
+ matched, l, c = pattern.match(l, c)
+ if not matched:
+ return False, left, collected
+ return True, l, c
+
+
+class Optional(BranchPattern):
+
+ def match(self, left, collected=None):
+ collected = [] if collected is None else collected
+ for pattern in self.children:
+ m, left, collected = pattern.match(left, collected)
+ return True, left, collected
+
+
+class OptionsShortcut(Optional):
+
+ """Marker/placeholder for [options] shortcut."""
+
+
+class OneOrMore(BranchPattern):
+
+ def match(self, left, collected=None):
+ assert len(self.children) == 1
+ collected = [] if collected is None else collected
+ l = left
+ c = collected
+ l_ = None
+ matched = True
+ times = 0
+ while matched:
+ # could it be that something didn't match but changed l or c?
+ matched, l, c = self.children[0].match(l, c)
+ times += 1 if matched else 0
+ if l_ == l:
+ break
+ l_ = l
+ if times >= 1:
+ return True, l, c
+ return False, left, collected
+
+
+class Either(BranchPattern):
+
+ def match(self, left, collected=None):
+ collected = [] if collected is None else collected
+ outcomes = []
+ for pattern in self.children:
+ matched, _, _ = outcome = pattern.match(left, collected)
+ if matched:
+ outcomes.append(outcome)
+ if outcomes:
+ return min(outcomes, key=lambda outcome: len(outcome[1]))
+ return False, left, collected
+
+
+class Tokens(list):
+
+ def __init__(self, source, error=DocoptExit):
+ self += source.split() if hasattr(source, 'split') else source
+ self.error = error
+
+ @staticmethod
+ def from_pattern(source):
+ source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source)
+ source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s]
+ return Tokens(source, error=DocoptLanguageError)
+
+ def move(self):
+ return self.pop(0) if len(self) else None
+
+ def current(self):
+ return self[0] if len(self) else None
+
+
+def parse_long(tokens, options):
+ """long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
+ long, eq, value = tokens.move().partition('=')
+ assert long.startswith('--')
+ value = None if eq == value == '' else value
+ similar = [o for o in options if o.long == long]
+ if tokens.error is DocoptExit and similar == []: # if no exact match
+ similar = [o for o in options if o.long and o.long.startswith(long)]
+ if len(similar) > 1: # might be simply specified ambiguously 2+ times?
+ raise tokens.error('%s is not a unique prefix: %s?' %
+ (long, ', '.join(o.long for o in similar)))
+ elif len(similar) < 1:
+ argcount = 1 if eq == '=' else 0
+ o = Option(None, long, argcount)
+ options.append(o)
+ if tokens.error is DocoptExit:
+ o = Option(None, long, argcount, value if argcount else True)
+ else:
+ o = Option(similar[0].short, similar[0].long,
+ similar[0].argcount, similar[0].value)
+ if o.argcount == 0:
+ if value is not None:
+ raise tokens.error('%s must not have an argument' % o.long)
+ else:
+ if value is None:
+ if tokens.current() in [None, '--']:
+ raise tokens.error('%s requires argument' % o.long)
+ value = tokens.move()
+ if tokens.error is DocoptExit:
+ o.value = value if value is not None else True
+ return [o]
+
+
+def parse_shorts(tokens, options):
+ """shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
+ token = tokens.move()
+ assert token.startswith('-') and not token.startswith('--')
+ left = token.lstrip('-')
+ parsed = []
+ while left != '':
+ short, left = '-' + left[0], left[1:]
+ similar = [o for o in options if o.short == short]
+ if len(similar) > 1:
+ raise tokens.error('%s is specified ambiguously %d times' %
+ (short, len(similar)))
+ elif len(similar) < 1:
+ o = Option(short, None, 0)
+ options.append(o)
+ if tokens.error is DocoptExit:
+ o = Option(short, None, 0, True)
+ else: # why copying is necessary here?
+ o = Option(short, similar[0].long,
+ similar[0].argcount, similar[0].value)
+ value = None
+ if o.argcount != 0:
+ if left == '':
+ if tokens.current() in [None, '--']:
+ raise tokens.error('%s requires argument' % short)
+ value = tokens.move()
+ else:
+ value = left
+ left = ''
+ if tokens.error is DocoptExit:
+ o.value = value if value is not None else True
+ parsed.append(o)
+ return parsed
+
+
+def parse_pattern(source, options):
+ tokens = Tokens.from_pattern(source)
+ result = parse_expr(tokens, options)
+ if tokens.current() is not None:
+ raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
+ return Required(*result)
+
+
+def parse_expr(tokens, options):
+ """expr ::= seq ( '|' seq )* ;"""
+ seq = parse_seq(tokens, options)
+ if tokens.current() != '|':
+ return seq
+ result = [Required(*seq)] if len(seq) > 1 else seq
+ while tokens.current() == '|':
+ tokens.move()
+ seq = parse_seq(tokens, options)
+ result += [Required(*seq)] if len(seq) > 1 else seq
+ return [Either(*result)] if len(result) > 1 else result
+
+
+def parse_seq(tokens, options):
+ """seq ::= ( atom [ '...' ] )* ;"""
+ result = []
+ while tokens.current() not in [None, ']', ')', '|']:
+ atom = parse_atom(tokens, options)
+ if tokens.current() == '...':
+ atom = [OneOrMore(*atom)]
+ tokens.move()
+ result += atom
+ return result
+
+
+def parse_atom(tokens, options):
+ """atom ::= '(' expr ')' | '[' expr ']' | 'options'
+ | long | shorts | argument | command ;
+ """
+ token = tokens.current()
+ result = []
+ if token in '([':
+ tokens.move()
+ matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
+ result = pattern(*parse_expr(tokens, options))
+ if tokens.move() != matching:
+ raise tokens.error("unmatched '%s'" % token)
+ return [result]
+ elif token == 'options':
+ tokens.move()
+ return [OptionsShortcut()]
+ elif token.startswith('--') and token != '--':
+ return parse_long(tokens, options)
+ elif token.startswith('-') and token not in ('-', '--'):
+ return parse_shorts(tokens, options)
+ elif token.startswith('<') and token.endswith('>') or token.isupper():
+ return [Argument(tokens.move())]
+ else:
+ return [Command(tokens.move())]
+
+
+def parse_argv(tokens, options, options_first=False):
+ """Parse command-line argument vector.
+
+ If options_first:
+ argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
+ else:
+ argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
+
+ """
+ parsed = []
+ while tokens.current() is not None:
+ if tokens.current() == '--':
+ return parsed + [Argument(None, v) for v in tokens]
+ elif tokens.current().startswith('--'):
+ parsed += parse_long(tokens, options)
+ elif tokens.current().startswith('-') and tokens.current() != '-':
+ parsed += parse_shorts(tokens, options)
+ elif options_first:
+ return parsed + [Argument(None, v) for v in tokens]
+ else:
+ parsed.append(Argument(None, tokens.move()))
+ return parsed
+
+
+def parse_defaults(doc):
+ defaults = []
+ for s in parse_section('options:', doc):
+ # FIXME corner case "bla: options: --foo"
+ _, _, s = s.partition(':') # get rid of "options:"
+ split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:]
+ split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
+ options = [Option.parse(s) for s in split if s.startswith('-')]
+ defaults += options
+ return defaults
+
+
+def parse_section(name, source):
+ pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
+ re.IGNORECASE | re.MULTILINE)
+ return [s.strip() for s in pattern.findall(source)]
+
+
+def formal_usage(section):
+ _, _, section = section.partition(':') # drop "usage:"
+ pu = section.split()
+ return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
+
+
+def extras(help, version, options, doc):
+ if help and any((o.name in ('-h', '--help')) and o.value for o in options):
+ print(doc.strip("\n"))
+ sys.exit()
+ if version and any(o.name == '--version' and o.value for o in options):
+ print(version)
+ sys.exit()
+
+
+class Dict(dict):
+ def __repr__(self):
+ return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
+
+
+def docopt(doc, argv=None, help=True, version=None, options_first=False):
+ """Parse `argv` based on command-line interface described in `doc`.
+
+ `docopt` creates your command-line interface based on its
+ description that you pass as `doc`. Such description can contain
+ --options, <positional-argument>, commands, which could be
+ [optional], (required), (mutually | exclusive) or repeated...
+
+ Parameters
+ ----------
+ doc : str
+ Description of your command-line interface.
+ argv : list of str, optional
+ Argument vector to be parsed. sys.argv[1:] is used if not
+ provided.
+ help : bool (default: True)
+ Set to False to disable automatic help on -h or --help
+ options.
+ version : any object
+ If passed, the object will be printed if --version is in
+ `argv`.
+ options_first : bool (default: False)
+ Set to True to require options precede positional arguments,
+ i.e. to forbid options and positional arguments intermix.
+
+ Returns
+ -------
+ args : dict
+ A dictionary, where keys are names of command-line elements
+ such as e.g. "--verbose" and "<path>", and values are the
+ parsed values of those elements.
+
+ Example
+ -------
+ >>> from docopt import docopt
+ >>> doc = '''
+ ... Usage:
+ ... my_program tcp <host> <port> [--timeout=<seconds>]
+ ... my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
+ ... my_program (-h | --help | --version)
+ ...
+ ... Options:
+ ... -h, --help Show this screen and exit.
+ ... --baud=<n> Baudrate [default: 9600]
+ ... '''
+ >>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
+ >>> docopt(doc, argv)
+ {'--baud': '9600',
+ '--help': False,
+ '--timeout': '30',
+ '--version': False,
+ '<host>': '127.0.0.1',
+ '<port>': '80',
+ 'serial': False,
+ 'tcp': True}
+
+ See also
+ --------
+ * For video introduction see http://docopt.org
+ * Full documentation is available in README.rst as well as online
+ at https://github.com/docopt/docopt#readme
+
+ """
+ argv = sys.argv[1:] if argv is None else argv
+
+ usage_sections = parse_section('usage:', doc)
+ if len(usage_sections) == 0:
+ raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
+ if len(usage_sections) > 1:
+ raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
+ DocoptExit.usage = usage_sections[0]
+
+ options = parse_defaults(doc)
+ pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
+ # [default] syntax for argument is disabled
+ #for a in pattern.flat(Argument):
+ # same_name = [d for d in arguments if d.name == a.name]
+ # if same_name:
+ # a.value = same_name[0].value
+ argv = parse_argv(Tokens(argv), list(options), options_first)
+ pattern_options = set(pattern.flat(Option))
+ for options_shortcut in pattern.flat(OptionsShortcut):
+ doc_options = parse_defaults(doc)
+ options_shortcut.children = list(set(doc_options) - pattern_options)
+ #if any_options:
+ # options_shortcut.children += [Option(o.short, o.long, o.argcount)
+ # for o in argv if type(o) is Option]
+ extras(help, version, argv, doc)
+ matched, left, collected = pattern.fix().match(argv)
+ if matched and left == []: # better error message if left?
+ return Dict((a.name, a.value) for a in (pattern.flat() + collected))
+ raise DocoptExit()
diff --git a/thirdparty/fmt/support/mkdocs b/thirdparty/fmt/support/mkdocs
new file mode 100755
index 000000000..610d81d67
--- /dev/null
+++ b/thirdparty/fmt/support/mkdocs
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# A script to invoke mkdocs with the correct environment.
+# Additionally supports deploying via mike:
+# ./mkdocs deploy [mike-deploy-options]
+
+import errno, os, shutil, sys
+from subprocess import call
+
+support_dir = os.path.dirname(os.path.normpath(__file__))
+build_dir = os.path.join(os.path.dirname(support_dir), 'build')
+
+# Set PYTHONPATH for the mkdocstrings handler.
+env = os.environ.copy()
+path = env.get('PYTHONPATH')
+env['PYTHONPATH'] = \
+ (path + ':' if path else '') + os.path.join(support_dir, 'python')
+
+redirect_page = \
+'''<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Redirecting</title>
+ <noscript>
+ <meta http-equiv="refresh" content="1; url=11.0/" />
+ </noscript>
+ <script>
+ window.location.replace(
+ "api/" + window.location.search + window.location.hash
+ );
+ </script>
+</head>
+<body>
+ Redirecting to <a href="api/">api</a>...
+</body>
+</html>
+'''
+
+config_path = os.path.join(support_dir, 'mkdocs.yml')
+args = sys.argv[1:]
+if len(args) > 0:
+ command = args[0]
+ if command == 'deploy':
+ git_url = 'https://github.com/' if 'CI' in os.environ else '[email protected]:'
+ site_repo = git_url + 'fmtlib/fmt.dev.git'
+
+ site_dir = os.path.join(build_dir, 'fmt.dev')
+ try:
+ shutil.rmtree(site_dir)
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ pass
+ ret = call(['git', 'clone', '--depth=1', site_repo, site_dir])
+ if ret != 0:
+ sys.exit(ret)
+
+ # Copy the config to the build dir because the site is built relative to it.
+ config_build_path = os.path.join(build_dir, 'mkdocs.yml')
+ shutil.copyfile(config_path, config_build_path)
+
+ version = args[1]
+ ret = call(['mike'] + args + ['--config-file', config_build_path,
+ '--branch', 'master'], cwd=site_dir, env=env)
+ if ret != 0 or version == 'dev':
+ sys.exit(ret)
+ current_doc_path = os.path.join(site_dir, version)
+ os.makedirs(current_doc_path, exist_ok=True)
+ redirect_page_path = os.path.join(current_doc_path, 'api.html')
+ with open(redirect_page_path, "w") as file:
+ file.write(redirect_page)
+ ret = call(['git', 'add', redirect_page_path], cwd=site_dir)
+ if ret != 0:
+ sys.exit(ret)
+ ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir)
+ sys.exit(ret)
+ elif not command.startswith('-'):
+ args += ['-f', config_path]
+sys.exit(call(['mkdocs'] + args, env=env))
diff --git a/thirdparty/fmt/support/mkdocs.yml b/thirdparty/fmt/support/mkdocs.yml
new file mode 100644
index 000000000..17034cd1f
--- /dev/null
+++ b/thirdparty/fmt/support/mkdocs.yml
@@ -0,0 +1,48 @@
+site_name: '{fmt}'
+
+docs_dir: ../doc
+
+repo_url: https://github.com/fmtlib/fmt
+
+theme:
+ name: material
+ features:
+ - navigation.tabs
+ - navigation.top
+ - toc.integrate
+
+extra_javascript:
+ - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js
+ - fmt.js
+
+extra_css:
+ - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css
+ - fmt.css
+
+markdown_extensions:
+ - pymdownx.highlight:
+ # Use JavaScript syntax highlighter instead of Pygments because it
+ # automatically applies to code blocks extracted through Doxygen.
+ use_pygments: false
+ anchor_linenums: true
+ line_spans: __span
+ pygments_lang_class: true
+ - pymdownx.inlinehilite
+ - pymdownx.snippets
+
+plugins:
+ - search
+ - mkdocstrings:
+ default_handler: cxx
+nav:
+ - Home: index.md
+ - Get Started: get-started.md
+ - API: api.md
+ - Syntax: syntax.md
+
+exclude_docs: ChangeLog-old.md
+
+extra:
+ version:
+ provider: mike
+ generator: false
diff --git a/thirdparty/fmt/support/printable.py b/thirdparty/fmt/support/printable.py
new file mode 100755
index 000000000..8fa86b300
--- /dev/null
+++ b/thirdparty/fmt/support/printable.py
@@ -0,0 +1,201 @@
+#!/usr/bin/env python3
+
+# This script is based on
+# https://github.com/rust-lang/rust/blob/master/library/core/src/unicode/printable.py
+# distributed under https://github.com/rust-lang/rust/blob/master/LICENSE-MIT.
+
+# This script uses the following Unicode tables:
+# - UnicodeData.txt
+
+
+from collections import namedtuple
+import csv
+import os
+import subprocess
+
+NUM_CODEPOINTS=0x110000
+
+def to_ranges(iter):
+ current = None
+ for i in iter:
+ if current is None or i != current[1] or i in (0x10000, 0x20000):
+ if current is not None:
+ yield tuple(current)
+ current = [i, i + 1]
+ else:
+ current[1] += 1
+ if current is not None:
+ yield tuple(current)
+
+def get_escaped(codepoints):
+ for c in codepoints:
+ if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '):
+ yield c.value
+
+def get_file(f):
+ try:
+ return open(os.path.basename(f))
+ except FileNotFoundError:
+ subprocess.run(["curl", "-O", f], check=True)
+ return open(os.path.basename(f))
+
+Codepoint = namedtuple('Codepoint', 'value class_')
+
+def get_codepoints(f):
+ r = csv.reader(f, delimiter=";")
+ prev_codepoint = 0
+ class_first = None
+ for row in r:
+ codepoint = int(row[0], 16)
+ name = row[1]
+ class_ = row[2]
+
+ if class_first is not None:
+ if not name.endswith("Last>"):
+ raise ValueError("Missing Last after First")
+
+ for c in range(prev_codepoint + 1, codepoint):
+ yield Codepoint(c, class_first)
+
+ class_first = None
+ if name.endswith("First>"):
+ class_first = class_
+
+ yield Codepoint(codepoint, class_)
+ prev_codepoint = codepoint
+
+ if class_first is not None:
+ raise ValueError("Missing Last after First")
+
+ for c in range(prev_codepoint + 1, NUM_CODEPOINTS):
+ yield Codepoint(c, None)
+
+def compress_singletons(singletons):
+ uppers = [] # (upper, # items in lowers)
+ lowers = []
+
+ for i in singletons:
+ upper = i >> 8
+ lower = i & 0xff
+ if len(uppers) == 0 or uppers[-1][0] != upper:
+ uppers.append((upper, 1))
+ else:
+ upper, count = uppers[-1]
+ uppers[-1] = upper, count + 1
+ lowers.append(lower)
+
+ return uppers, lowers
+
+def compress_normal(normal):
+ # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f
+ # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff
+ compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)]
+
+ prev_start = 0
+ for start, count in normal:
+ truelen = start - prev_start
+ falselen = count
+ prev_start = start + count
+
+ assert truelen < 0x8000 and falselen < 0x8000
+ entry = []
+ if truelen > 0x7f:
+ entry.append(0x80 | (truelen >> 8))
+ entry.append(truelen & 0xff)
+ else:
+ entry.append(truelen & 0x7f)
+ if falselen > 0x7f:
+ entry.append(0x80 | (falselen >> 8))
+ entry.append(falselen & 0xff)
+ else:
+ entry.append(falselen & 0x7f)
+
+ compressed.append(entry)
+
+ return compressed
+
+def print_singletons(uppers, lowers, uppersname, lowersname):
+ print(" static constexpr singleton {}[] = {{".format(uppersname))
+ for u, c in uppers:
+ print(" {{{:#04x}, {}}},".format(u, c))
+ print(" };")
+ print(" static constexpr unsigned char {}[] = {{".format(lowersname))
+ for i in range(0, len(lowers), 8):
+ print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
+ print(" };")
+
+def print_normal(normal, normalname):
+ print(" static constexpr unsigned char {}[] = {{".format(normalname))
+ for v in normal:
+ print(" {}".format(" ".join("{:#04x},".format(i) for i in v)))
+ print(" };")
+
+def main():
+ file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
+
+ codepoints = get_codepoints(file)
+
+ CUTOFF=0x10000
+ singletons0 = []
+ singletons1 = []
+ normal0 = []
+ normal1 = []
+ extra = []
+
+ for a, b in to_ranges(get_escaped(codepoints)):
+ if a > 2 * CUTOFF:
+ extra.append((a, b - a))
+ elif a == b - 1:
+ if a & CUTOFF:
+ singletons1.append(a & ~CUTOFF)
+ else:
+ singletons0.append(a)
+ elif a == b - 2:
+ if a & CUTOFF:
+ singletons1.append(a & ~CUTOFF)
+ singletons1.append((a + 1) & ~CUTOFF)
+ else:
+ singletons0.append(a)
+ singletons0.append(a + 1)
+ else:
+ if a >= 2 * CUTOFF:
+ extra.append((a, b - a))
+ elif a & CUTOFF:
+ normal1.append((a & ~CUTOFF, b - a))
+ else:
+ normal0.append((a, b - a))
+
+ singletons0u, singletons0l = compress_singletons(singletons0)
+ singletons1u, singletons1l = compress_singletons(singletons1)
+ normal0 = compress_normal(normal0)
+ normal1 = compress_normal(normal1)
+
+ print("""\
+FMT_FUNC auto is_printable(uint32_t cp) -> bool {\
+""")
+ print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
+ print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
+ print_normal(normal0, 'normal0')
+ print_normal(normal1, 'normal1')
+ print("""\
+ auto lower = static_cast<uint16_t>(cp);
+ if (cp < 0x10000) {
+ return is_printable(lower, singletons0,
+ sizeof(singletons0) / sizeof(*singletons0),
+ singletons0_lower, normal0, sizeof(normal0));
+ }
+ if (cp < 0x20000) {
+ return is_printable(lower, singletons1,
+ sizeof(singletons1) / sizeof(*singletons1),
+ singletons1_lower, normal1, sizeof(normal1));
+ }\
+""")
+ for a, b in extra:
+ print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b))
+ print("""\
+ return cp < 0x{:x};
+}}\
+""".format(NUM_CODEPOINTS))
+
+if __name__ == '__main__':
+ main()
diff --git a/thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/__init__.py b/thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/__init__.py
new file mode 100644
index 000000000..85d52a580
--- /dev/null
+++ b/thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/__init__.py
@@ -0,0 +1,338 @@
+# A basic mkdocstrings handler for {fmt}.
+# Copyright (c) 2012 - present, Victor Zverovich
+# https://github.com/fmtlib/fmt/blob/master/LICENSE
+
+import os
+import xml.etree.ElementTree as ElementTree
+from pathlib import Path
+from subprocess import PIPE, STDOUT, CalledProcessError, Popen
+from typing import Any, List, Mapping, Optional
+
+from mkdocstrings.handlers.base import BaseHandler
+
+
+class Definition:
+ """A definition extracted by Doxygen."""
+
+ def __init__(self, name: str, kind: Optional[str] = None,
+ node: Optional[ElementTree.Element] = None,
+ is_member: bool = False):
+ self.name = name
+ self.kind = kind if kind is not None else node.get('kind')
+ self.desc = None
+ self.id = name if not is_member else None
+ self.members = None
+ self.params = None
+ self.template_params = None
+ self.trailing_return_type = None
+ self.type = None
+
+
+# A map from Doxygen to HTML tags.
+tag_map = {
+ 'bold': 'b',
+ 'emphasis': 'em',
+ 'computeroutput': 'code',
+ 'para': 'p',
+ 'programlisting': 'pre',
+ 'verbatim': 'pre'
+}
+
+# A map from Doxygen tags to text.
+tag_text_map = {
+ 'codeline': '',
+ 'highlight': '',
+ 'sp': ' '
+}
+
+
+def escape_html(s: str) -> str:
+ return s.replace("<", "&lt;")
+
+
+def doxyxml2html(nodes: List[ElementTree.Element]):
+ out = ''
+ for n in nodes:
+ tag = tag_map.get(n.tag)
+ if not tag:
+ out += tag_text_map[n.tag]
+ out += '<' + tag + '>' if tag else ''
+ out += '<code class="language-cpp">' if tag == 'pre' else ''
+ if n.text:
+ out += escape_html(n.text)
+ out += doxyxml2html(list(n))
+ out += '</code>' if tag == 'pre' else ''
+ out += '</' + tag + '>' if tag else ''
+ if n.tail:
+ out += n.tail
+ return out
+
+
+def convert_template_params(node: ElementTree.Element) -> Optional[List[Definition]]:
+ template_param_list = node.find('templateparamlist')
+ if template_param_list is None:
+ return None
+ params = []
+ for param_node in template_param_list.findall('param'):
+ name = param_node.find('declname')
+ param = Definition(name.text if name is not None else '', 'param')
+ param.type = param_node.find('type').text
+ params.append(param)
+ return params
+
+
+def get_description(node: ElementTree.Element) -> List[ElementTree.Element]:
+ return node.findall('briefdescription/para') + \
+ node.findall('detaileddescription/para')
+
+
+def normalize_type(type_: str) -> str:
+ type_ = type_.replace('< ', '<').replace(' >', '>')
+ return type_.replace(' &', '&').replace(' *', '*')
+
+
+def convert_type(type_: ElementTree.Element) -> Optional[str]:
+ if type_ is None:
+ return None
+ result = type_.text if type_.text else ''
+ for ref in type_:
+ result += ref.text
+ if ref.tail:
+ result += ref.tail
+ result += type_.tail.strip()
+ return normalize_type(result)
+
+
+def convert_params(func: ElementTree.Element) -> List[Definition]:
+ params = []
+ for p in func.findall('param'):
+ d = Definition(p.find('declname').text, 'param')
+ d.type = convert_type(p.find('type'))
+ params.append(d)
+ return params
+
+
+def convert_return_type(d: Definition, node: ElementTree.Element) -> None:
+ d.trailing_return_type = None
+ if d.type == 'auto' or d.type == 'constexpr auto':
+ parts = node.find('argsstring').text.split(' -> ')
+ if len(parts) > 1:
+ d.trailing_return_type = normalize_type(parts[1])
+
+
+def render_param(param: Definition) -> str:
+ return param.type + (f'&nbsp;{param.name}' if len(param.name) > 0 else '')
+
+
+def render_decl(d: Definition) -> str:
+ text = ''
+ if d.id is not None:
+ text += f'<a id="{d.id}">\n'
+ text += '<pre><code class="language-cpp decl">'
+
+ text += '<div>'
+ if d.template_params is not None:
+ text += 'template &lt;'
+ text += ', '.join([render_param(p) for p in d.template_params])
+ text += '&gt;\n'
+ text += '</div>'
+
+ text += '<div>'
+ end = ';'
+ if d.kind == 'function' or d.kind == 'variable':
+ text += d.type + ' ' if len(d.type) > 0 else ''
+ elif d.kind == 'typedef':
+ text += 'using '
+ elif d.kind == 'define':
+ end = ''
+ else:
+ text += d.kind + ' '
+ text += d.name
+
+ if d.params is not None:
+ params = ', '.join([
+ (p.type + ' ' if p.type else '') + p.name for p in d.params])
+ text += '(' + escape_html(params) + ')'
+ if d.trailing_return_type:
+ text += ' -&NoBreak;>&nbsp;' + escape_html(d.trailing_return_type)
+ elif d.kind == 'typedef':
+ text += ' = ' + escape_html(d.type)
+
+ text += end
+ text += '</div>'
+ text += '</code></pre>\n'
+ if d.id is not None:
+ text += f'</a>\n'
+ return text
+
+
+class CxxHandler(BaseHandler):
+ def __init__(self, **kwargs: Any) -> None:
+ super().__init__(handler='cxx', **kwargs)
+
+ headers = [
+ 'args.h', 'base.h', 'chrono.h', 'color.h', 'compile.h', 'format.h',
+ 'os.h', 'ostream.h', 'printf.h', 'ranges.h', 'std.h', 'xchar.h'
+ ]
+
+ # Run doxygen.
+ cmd = ['doxygen', '-']
+ support_dir = Path(__file__).parents[3]
+ top_dir = os.path.dirname(support_dir)
+ include_dir = os.path.join(top_dir, 'include', 'fmt')
+ self._ns2doxyxml = {}
+ build_dir = os.path.join(top_dir, 'build')
+ os.makedirs(build_dir, exist_ok=True)
+ self._doxyxml_dir = os.path.join(build_dir, 'doxyxml')
+ p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
+ _, _ = p.communicate(input=r'''
+ PROJECT_NAME = fmt
+ GENERATE_XML = YES
+ GENERATE_LATEX = NO
+ GENERATE_HTML = NO
+ INPUT = {0}
+ XML_OUTPUT = {1}
+ QUIET = YES
+ AUTOLINK_SUPPORT = NO
+ MACRO_EXPANSION = YES
+ PREDEFINED = _WIN32=1 \
+ __linux__=1 \
+ FMT_ENABLE_IF(...)= \
+ FMT_USE_USER_LITERALS=1 \
+ FMT_USE_ALIAS_TEMPLATES=1 \
+ FMT_USE_NONTYPE_TEMPLATE_ARGS=1 \
+ FMT_API= \
+ "FMT_BEGIN_NAMESPACE=namespace fmt {{" \
+ "FMT_END_NAMESPACE=}}" \
+ "FMT_DOC=1"
+ '''.format(
+ ' '.join([os.path.join(include_dir, h) for h in headers]),
+ self._doxyxml_dir).encode('utf-8'))
+ if p.returncode != 0:
+ raise CalledProcessError(p.returncode, cmd)
+
+ # Merge all file-level XMLs into one to simplify search.
+ self._file_doxyxml = None
+ for h in headers:
+ filename = h.replace(".h", "_8h.xml")
+ with open(os.path.join(self._doxyxml_dir, filename)) as f:
+ doxyxml = ElementTree.parse(f)
+ if self._file_doxyxml is None:
+ self._file_doxyxml = doxyxml
+ continue
+ root = self._file_doxyxml.getroot()
+ for node in doxyxml.getroot():
+ root.append(node)
+
+ def collect_compound(self, identifier: str,
+ cls: List[ElementTree.Element]) -> Definition:
+ """Collect a compound definition such as a struct."""
+ path = os.path.join(self._doxyxml_dir, cls[0].get('refid') + '.xml')
+ with open(path) as f:
+ xml = ElementTree.parse(f)
+ node = xml.find('compounddef')
+ d = Definition(identifier, node=node)
+ d.template_params = convert_template_params(node)
+ d.desc = get_description(node)
+ d.members = []
+ for m in \
+ node.findall('sectiondef[@kind="public-attrib"]/memberdef') + \
+ node.findall('sectiondef[@kind="public-func"]/memberdef'):
+ name = m.find('name').text
+ # Doxygen incorrectly classifies members of private unnamed unions as
+ # public members of the containing class.
+ if name.endswith('_'):
+ continue
+ desc = get_description(m)
+ if len(desc) == 0:
+ continue
+ kind = m.get('kind')
+ member = Definition(name if name else '', kind=kind, is_member=True)
+ type_text = m.find('type').text
+ member.type = type_text if type_text else ''
+ if kind == 'function':
+ member.params = convert_params(m)
+ convert_return_type(member, m)
+ member.template_params = None
+ member.desc = desc
+ d.members.append(member)
+ return d
+
+ def collect(self, identifier: str, _config: Mapping[str, Any]) -> Definition:
+ qual_name = 'fmt::' + identifier
+
+ param_str = None
+ paren = qual_name.find('(')
+ if paren > 0:
+ qual_name, param_str = qual_name[:paren], qual_name[paren + 1:-1]
+
+ colons = qual_name.rfind('::')
+ namespace, name = qual_name[:colons], qual_name[colons + 2:]
+
+ # Load XML.
+ doxyxml = self._ns2doxyxml.get(namespace)
+ if doxyxml is None:
+ path = f'namespace{namespace.replace("::", "_1_1")}.xml'
+ with open(os.path.join(self._doxyxml_dir, path)) as f:
+ doxyxml = ElementTree.parse(f)
+ self._ns2doxyxml[namespace] = doxyxml
+
+ nodes = doxyxml.findall(
+ f"compounddef/sectiondef/memberdef/name[.='{name}']/..")
+ if len(nodes) == 0:
+ nodes = self._file_doxyxml.findall(
+ f"compounddef/sectiondef/memberdef/name[.='{name}']/..")
+ candidates = []
+ for node in nodes:
+ # Process a function or a typedef.
+ params = None
+ d = Definition(name, node=node)
+ if d.kind == 'function':
+ params = convert_params(node)
+ node_param_str = ', '.join([p.type for p in params])
+ if param_str and param_str != node_param_str:
+ candidates.append(f'{name}({node_param_str})')
+ continue
+ elif d.kind == 'define':
+ params = []
+ for p in node.findall('param'):
+ param = Definition(p.find('defname').text, kind='param')
+ param.type = None
+ params.append(param)
+ d.type = convert_type(node.find('type'))
+ d.template_params = convert_template_params(node)
+ d.params = params
+ convert_return_type(d, node)
+ d.desc = get_description(node)
+ return d
+
+ cls = doxyxml.findall(f"compounddef/innerclass[.='{qual_name}']")
+ if not cls:
+ raise Exception(f'Cannot find {identifier}. Candidates: {candidates}')
+ return self.collect_compound(identifier, cls)
+
+ def render(self, d: Definition, config: dict) -> str:
+ if d.id is not None:
+ self.do_heading('', 0, id=d.id)
+ text = '<div class="docblock">\n'
+ text += render_decl(d)
+ text += '<div class="docblock-desc">\n'
+ text += doxyxml2html(d.desc)
+ if d.members is not None:
+ for m in d.members:
+ text += self.render(m, config)
+ text += '</div>\n'
+ text += '</div>\n'
+ return text
+
+
+def get_handler(theme: str, custom_templates: Optional[str] = None,
+ **_config: Any) -> CxxHandler:
+ """Return an instance of `CxxHandler`.
+
+ Arguments:
+ theme: The theme to use when rendering contents.
+ custom_templates: Directory containing custom templates.
+ **_config: Configuration passed to the handler.
+ """
+ return CxxHandler(theme=theme, custom_templates=custom_templates)
diff --git a/thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/templates/README b/thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/templates/README
new file mode 100644
index 000000000..7da18db54
--- /dev/null
+++ b/thirdparty/fmt/support/python/mkdocstrings_handlers/cxx/templates/README
@@ -0,0 +1 @@
+mkdocsstrings requires a handler to have a templates directory.
diff --git a/thirdparty/fmt/support/release.py b/thirdparty/fmt/support/release.py
new file mode 100755
index 000000000..26de7f4fd
--- /dev/null
+++ b/thirdparty/fmt/support/release.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python3
+
+"""Make a release.
+
+Usage:
+ release.py [<branch>]
+
+For the release command $FMT_TOKEN should contain a GitHub personal access token
+obtained from https://github.com/settings/tokens.
+"""
+
+from __future__ import print_function
+import datetime, docopt, errno, fileinput, json, os
+import re, shutil, sys
+from subprocess import check_call
+import urllib.request
+
+
+class Git:
+ def __init__(self, dir):
+ self.dir = dir
+
+ def call(self, method, args, **kwargs):
+ return check_call(['git', method] + list(args), **kwargs)
+
+ def add(self, *args):
+ return self.call('add', args, cwd=self.dir)
+
+ def checkout(self, *args):
+ return self.call('checkout', args, cwd=self.dir)
+
+ def clean(self, *args):
+ return self.call('clean', args, cwd=self.dir)
+
+ def clone(self, *args):
+ return self.call('clone', list(args) + [self.dir])
+
+ def commit(self, *args):
+ return self.call('commit', args, cwd=self.dir)
+
+ def pull(self, *args):
+ return self.call('pull', args, cwd=self.dir)
+
+ def push(self, *args):
+ return self.call('push', args, cwd=self.dir)
+
+ def reset(self, *args):
+ return self.call('reset', args, cwd=self.dir)
+
+ def update(self, *args):
+ clone = not os.path.exists(self.dir)
+ if clone:
+ self.clone(*args)
+ return clone
+
+
+def clean_checkout(repo, branch):
+ repo.clean('-f', '-d')
+ repo.reset('--hard')
+ repo.checkout(branch)
+
+
+class Runner:
+ def __init__(self, cwd):
+ self.cwd = cwd
+
+ def __call__(self, *args, **kwargs):
+ kwargs['cwd'] = kwargs.get('cwd', self.cwd)
+ check_call(args, **kwargs)
+
+
+def create_build_env():
+ """Create a build environment."""
+ class Env:
+ pass
+ env = Env()
+ env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ env.build_dir = 'build'
+ env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt'))
+ return env
+
+
+if __name__ == '__main__':
+ args = docopt.docopt(__doc__)
+ env = create_build_env()
+ fmt_repo = env.fmt_repo
+
+ branch = args.get('<branch>')
+ if branch is None:
+ branch = 'master'
+ if not fmt_repo.update('-b', branch, '[email protected]:fmtlib/fmt'):
+ clean_checkout(fmt_repo, branch)
+
+ # Update the date in the changelog and extract the version and the first
+ # section content.
+ changelog = 'ChangeLog.md'
+ changelog_path = os.path.join(fmt_repo.dir, changelog)
+ is_first_section = True
+ first_section = []
+ for i, line in enumerate(fileinput.input(changelog_path, inplace=True)):
+ if i == 0:
+ version = re.match(r'# (.*) - TBD', line).group(1)
+ line = '# {} - {}\n'.format(
+ version, datetime.date.today().isoformat())
+ elif not is_first_section:
+ pass
+ elif line.startswith('#'):
+ is_first_section = False
+ else:
+ first_section.append(line)
+ sys.stdout.write(line)
+ if first_section[0] == '\n':
+ first_section.pop(0)
+
+ ns_version = None
+ base_h_path = os.path.join(fmt_repo.dir, 'include', 'fmt', 'base.h')
+ for line in fileinput.input(base_h_path):
+ m = re.match(r'\s*inline namespace v(.*) .*', line)
+ if m:
+ ns_version = m.group(1)
+ break
+ major_version = version.split('.')[0]
+ if not ns_version or ns_version != major_version:
+ raise Exception(f'Version mismatch {ns_version} != {major_version}')
+
+ # Workaround GitHub-flavored Markdown treating newlines as <br>.
+ changes = ''
+ code_block = False
+ stripped = False
+ for line in first_section:
+ if re.match(r'^\s*```', line):
+ code_block = not code_block
+ changes += line
+ stripped = False
+ continue
+ if code_block:
+ changes += line
+ continue
+ if line == '\n' or re.match(r'^\s*\|.*', line):
+ if stripped:
+ changes += '\n'
+ stripped = False
+ changes += line
+ continue
+ if stripped:
+ line = ' ' + line.lstrip()
+ changes += line.rstrip()
+ stripped = True
+
+ fmt_repo.checkout('-B', 'release')
+ fmt_repo.add(changelog)
+ fmt_repo.commit('-m', 'Update version')
+
+ # Build the docs and package.
+ run = Runner(fmt_repo.dir)
+ run('cmake', '.')
+ run('make', 'doc', 'package_source')
+
+ # Create a release on GitHub.
+ fmt_repo.push('origin', 'release')
+ auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')}
+ req = urllib.request.Request(
+ 'https://api.github.com/repos/fmtlib/fmt/releases',
+ data=json.dumps({'tag_name': version,
+ 'target_commitish': 'release',
+ 'body': changes, 'draft': True}).encode('utf-8'),
+ headers=auth_headers, method='POST')
+ with urllib.request.urlopen(req) as response:
+ if response.status != 201:
+ raise Exception(f'Failed to create a release ' +
+ '{response.status} {response.reason}')
+ response_data = json.loads(response.read().decode('utf-8'))
+ id = response_data['id']
+
+ # Upload the package.
+ uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
+ package = 'fmt-{}.zip'.format(version)
+ req = urllib.request.Request(
+ f'{uploads_url}/{id}/assets?name={package}',
+ headers={'Content-Type': 'application/zip'} | auth_headers,
+ data=open('build/fmt/' + package, 'rb').read(), method='POST')
+ with urllib.request.urlopen(req) as response:
+ if response.status != 201:
+ raise Exception(f'Failed to upload an asset '
+ '{response.status} {response.reason}')
+
+ short_version = '.'.join(version.split('.')[:-1])
+ check_call(['./mkdocs', 'deploy', short_version])