This commit is contained in:
2026-09-13 13:30:21 +08:00
commit a6bbd520cf
2744 changed files with 1598795 additions and 0 deletions
@@ -0,0 +1,61 @@
{
"config": {
"MD001": true, // header levels increment by 1
"MD002": true, // first header should be a top level header
"MD003": { "style": "atx" }, // header style
"MD004": { "style": "dash" }, // unordered list style - dash
// "MD005": false, // inconsistent indentation handled by prettier
"MD006": true, // bulleted lists at beginning of line
// "MD007": { "indent": 2 }, // handled by prettier
"MD009": true, // no trailing spaces
"MD010": true, // no hard tabs
"MD011": true, // reversed link syntax
"MD012": true, // multiple consecutive blank lines
"MD013": false, // line length ignored
// "MD014": false, // command syntax ignored
"MD018": true, // space after header style
"MD019": true, // no multiple spaces after header style
"MD020": true, // no spaces inside hashes
"MD021": true, // no spaces inside closing hashes
"MD022": true, // headers surrounded by blank lines
"MD023": true, // headers start at beginning of line
"MD024": { "siblings_only": true,"allow_different_nesting": true }, // duplicate headers allowed in different nests
"MD025": true, // only one H1
"MD026": { "punctuation": ".,;:" }, // no trailing punctuation
"MD027": true, // multiple spaces after blockquote
"MD028": true, // no blank lines inside blockquote
// "MD029": { "style": "ordered" }, // prettier handles numbering
// "MD030": { "ul_single": 1, "ol_single": 1, "ul_multi": 1, "ol_multi": 3 }, // prettier handles spacing
"MD031": true, // fenced code blocks surrounded by blank lines
// "MD032": false, // lists surrounded by blank lines, prettier handles
// "MD033": { "allowed_elements": "a, em, strong, code, del, ins, sup, sub" }, // inline HTML exceptions
"MD033": false,
// "MD034": false, // raw URLs allowed
"MD035": { "style": "---" }, // horizontal rule style
// "MD036": false, // strong vs emphasis ignored
"MD037": true, // no spaces inside emphasis
"MD038": true, // no spaces inside code spans
"MD039": true, // no spaces inside link text
"MD040": true, // require fenced language
"MD041": true, // first line is top-level header
// "MD042": false, // empty link disabled
"MD046": { "style": "fenced" }, // code block style
"MD047": true, // single newline at end
"MD048": true, // code fence style consistency ignored
// Newly enabled rules for testing:
"MD044": {
// proper names; empty list means default names only
"names": []
},
"MD049": { "style": "consistent" }, // emphasis style
"MD050": { "style": "consistent" }, // strong style
"MD051": true, // valid link fragments
"MD052": true, // reference links/images must use defined labels
"MD053": true, // flag unused or undefined link references
// Table-related rules: enable if you use tables
"MD055": true, // consistent pipe style
"MD056": true, // consistent column counts
"MD058": true // blank lines around tables
}
}
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""Print the CHANGELOG.md section for a version, for use as release notes.
VERSION accepts a tag name ("v2.7.0") or a plain version ("2.7.0"). Older
sections are titled with two components and a name, such as
"## Version 2.5: Help Formatter", so "2.5.0" also matches "## Version 2.5".
Each section keeps its own link definitions, so the output needs no fixup.
With --title, print the section heading instead of the body; this is the name
of the GitHub release.
"""
from __future__ import annotations
import argparse
import re
from pathlib import Path
def extract(text: str, version: str) -> tuple[str, str] | None:
"""Return the heading and the body of the section for a version."""
heads = list(re.finditer(r"^## (Version (\S+?):?(?:[ \t].*)?)$", text, re.M))
for candidate in (version, version.rsplit(".", 1)[0]):
for i, head in enumerate(heads):
if head.group(2) != candidate:
continue
end = heads[i + 1].start() if i + 1 < len(heads) else len(text)
return head.group(1), text[head.end() : end].strip()
return None
def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("version", help='tag ("v2.7.0") or version ("2.7.0")')
parser.add_argument("changelog", nargs="?", type=Path, default=Path("CHANGELOG.md"))
parser.add_argument(
"--title", action="store_true", help="print the heading, not the body"
)
args = parser.parse_args()
version = args.version.lstrip("v")
section = extract(args.changelog.read_text(encoding="utf-8"), version)
if section is None:
raise SystemExit(f"No '## Version {version}' section in {args.changelog}")
heading, notes = section
print(heading if args.title else notes)
if __name__ == "__main__":
main()
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env python3
import os
import re
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
config_h = os.path.join(base_path, "include", "CLI", "Version.hpp")
data = {"MAJOR": 0, "MINOR": 0, "PATCH": 0}
reg = re.compile(r"^\s*#define\s+CLI11_VERSION_([A-Z]+)\s+([0-9]+).*$")
with open(config_h, "r") as fp:
for l in fp:
m = reg.match(l)
if m:
data[m.group(1)] = int(m.group(2))
print("{}.{}.{}".format(data["MAJOR"], data["MINOR"], data["PATCH"]))
+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/env python
from __future__ import print_function, unicode_literals
import os
import re
import argparse
from subprocess import Popen, PIPE
import warnings
tag_str = r"""
^ # Begin of line
[/\s]+ # Whitespace or comment // chars
\[ # A literal [
{tag}: # The tag
(?P<name>[\w_]+) # name: group name
: # Colon
(?P<action>[\w_]+) # action: type of include
\] # A literal ]
\s* # Whitespace
$ # End of a line
(?P<content>.*) # All
^ # Begin of line
[/\s]+ # Whitespace or comment // chars
\[ # A literal [
{tag}: # The tag
(?P=name) # Repeated name
: # Colon
end # Literal "end"
\] # A literal ]
\s* # Whitespace
$ # End of a line
"""
DIR = os.path.dirname(os.path.abspath(__file__))
class HeaderGroups(dict):
def __init__(self, tag):
"""
A dictionary that also can read headers given a tag expression.
TODO: might have gone overboard on this one, could maybe be two functions.
"""
self.re_matcher = re.compile(
tag_str.format(tag=tag), re.MULTILINE | re.DOTALL | re.VERBOSE
)
super(HeaderGroups, self).__init__()
def read_header(self, filename):
"""
Read a header file in and add items to the dict, based on the item's action.
"""
with open(filename) as f:
inner = f.read()
matches = self.re_matcher.findall(inner)
if not matches:
warnings.warn(
"Failed to find any matches in {filename}".format(filename=filename)
)
for name, action, content in matches:
if action == "verbatim":
assert (
name not in self
), "{name} read in more than once! Quitting.".format(name=name)
self[name] = content
elif action == "set":
self[name] = self.get(name, set()) | set(content.strip().splitlines())
else:
raise RuntimeError("Action not understood, must be verbatim or set")
def post_process(self):
"""
Turn sets into multiple line strings.
"""
for key in self:
if isinstance(self[key], set):
self[key] = "\n".join(sorted(self[key]))
def make_header(output, main_header, files, tag, namespace, macro=None, version=None):
"""
Makes a single header given a main header template and a list of files.
"""
groups = HeaderGroups(tag)
# Set tag if possible to class variable
try:
proc = Popen(
["git", "describe", "--tags", "--always"], cwd=str(DIR), stdout=PIPE
)
out, _ = proc.communicate()
groups["git"] = out.decode("utf-8").strip() if proc.returncode == 0 else ""
except OSError:
groups["git"] = ""
for f in files:
if os.path.isdir(f):
continue
groups.read_header(f)
groups["namespace"] = namespace
groups["version"] = version or groups["git"]
groups.post_process()
with open(main_header) as f:
single_header = f.read().format(**groups)
if macro is not None:
before, after = macro
print("Converting macros", before, "->", after)
single_header.replace(before, after)
new_namespace = namespace + "::"
single_header = re.sub(r"\bCLI::\b", new_namespace, single_header)
if output is not None:
with open(output, "w") as f:
f.write(single_header)
print("Created", output)
else:
print(single_header)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
usage="Convert source to single header include. Can optionally add namespace and search-replace replacements (for macros).",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument("--output", default=None, help="Single header file output")
parser.add_argument(
"--main",
default="single-include/CLI11.hpp.in",
help="The main include file that defines the other files",
)
parser.add_argument("files", nargs="+", help="The header files")
parser.add_argument("--namespace", default="CLI", help="Set the namespace")
parser.add_argument("--tag", default="CLI11", help="Tag to look up")
parser.add_argument(
"--macro", nargs=2, help="Replaces OLD_PREFIX_ with NEW_PREFIX_"
)
parser.add_argument("--version", help="Include this version in the generated file")
args = parser.parse_args()
make_header(
args.output,
args.main,
args.files,
args.tag,
args.namespace,
args.macro,
args.version,
)
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env sh
set -evx
clang-format --version
git ls-files -- '*.cpp' '*.hpp' | xargs clang-format -sort-includes -i -style=file
git diff --exit-code --color
set +evx
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env sh
# Also good but untagged: CLANG_FORMAT=unibeautify/clang-format
# This might provide more control in the future: silkeh/clang:8 (etc)
CLANG_FORMAT=saschpe/clang-format:5.0.1
set -evx
docker run --rm ${CLANG_FORMAT} --version
docker run --rm --user $(id -u):$(id -g) -v "$(pwd)":/workdir -w /workdir ${CLANG_FORMAT} -style=file -sort-includes -i $(git ls-files -- '*.cpp' '*.hpp')
git diff --exit-code --color
set +evx
+25
View File
@@ -0,0 +1,25 @@
# include-what-you-use mapping file for CLI11.
#
# Both standard libraries make IWYU ask for a header that CLI11 must not
# include: libc++ (macOS) exposes private detail headers, libstdc++ (Linux)
# exposes the C headers behind <cXXX>. Name the C++ header instead.
#
# Prefer a symbol entry. An include entry only takes effect when the left side
# is private, and declaring a real C header private makes IWYU abort with a
# "same file seen with two different visibilities" assertion.
[
{ symbol: ["abs", private, "<cstdlib>", public] },
{ symbol: ["errno", private, "<cerrno>", public] },
{ symbol: ["getenv", private, "<cstdlib>", public] },
{ symbol: ["isprint", private, "<cctype>", public] },
{ symbol: ["strlen", private, "<cstring>", public] },
{ symbol: ["wcslen", private, "<cwchar>", public] },
# libc++ detail headers. These are private, so an include entry works and
# covers every symbol at once.
{ include: ["<_ctype.h>", private, "<cctype>", public] },
{ include: ["<_stdlib.h>", private, "<cstdlib>", public] },
{ include: ["<_string.h>", private, "<cstring>", public] },
{ include: ["<_wchar.h>", private, "<cwchar>", public] },
{ include: ["<__locale>", private, "<locale>", public] },
]