feat: add missing KF6 framework recipes
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Pipfile.lock
|
||||
@@ -0,0 +1,12 @@
|
||||
# kate: hl toml;
|
||||
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
click = "~= 8.0"
|
||||
jinja2 = "~= 3.0"
|
||||
lxml = "*"
|
||||
PyYAML = "*"
|
||||
@@ -0,0 +1,501 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language
|
||||
[
|
||||
<!-- NOTE See https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variable-references -->
|
||||
<!ENTITY var_ref_re "[/\.\+\-_0-9A-Za-z]+">
|
||||
<!-- NOTE See `cmGeneratorExpression::IsValidTargetName` -->
|
||||
<!ENTITY tgt_name_re "[A-Za-z0-9_\.\+\-]+">
|
||||
]>
|
||||
<!--
|
||||
This file is part of KDE's kate project.
|
||||
|
||||
SPDX-FileCopyrightText: 2004 Alexander Neundorf <neundorf@kde.org>
|
||||
SPDX-FileCopyrightText: 2005 Dominik Haumann <dhdev@gmx.de>
|
||||
SPDX-FileCopyrightText: 2007, 2008, 2013, 2014 Matthew Woehlke <mw_triad@users.sourceforge.net>
|
||||
SPDX-FileCopyrightText: 2013-2015, 2017-2023 Alex Turbov <i.zaufi@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
-->
|
||||
|
||||
<!-- ***** THIS FILE WAS GENERATED BY A SCRIPT - DO NOT EDIT *****
|
||||
$ cd data/generators
|
||||
$ ./generate-cmake-syntax.py cmake.yaml > ../syntax/cmake.xml
|
||||
-->
|
||||
|
||||
<language
|
||||
name="CMake"
|
||||
version="<!--{version}-->"
|
||||
kateversion="5.62"
|
||||
section="Other"
|
||||
extensions="CMakeLists.txt;*.cmake;*.cmake.in"
|
||||
style="CMake"
|
||||
mimetype="text/x-cmake"
|
||||
author="Alex Turbov (i.zaufi@gmail.com)"
|
||||
license="LGPLv2+"
|
||||
>
|
||||
<highlighting>
|
||||
|
||||
<list name="commands">
|
||||
<!--[- for command in commands ]-->
|
||||
<item><!--{command.name}--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<!--[- macro render_command_arg_lists(commands) ]-->
|
||||
<!--[- for command in commands -]-->
|
||||
<!--[- if command.named_args and command.named_args.kw ]-->
|
||||
<list name="<!--{command.name}-->_nargs">
|
||||
<!--[- for arg in command.named_args.kw ]-->
|
||||
<item><!--{arg}--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.special_args and command.special_args.kw ]-->
|
||||
<list name="<!--{command.name}-->_sargs">
|
||||
<!--[- for arg in command.special_args.kw ]-->
|
||||
<item><!--{arg}--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
<!--[- endif ]-->
|
||||
<!--[- endfor ]-->
|
||||
<!--[- endmacro ]-->
|
||||
<!--{- render_command_arg_lists(commands) }-->
|
||||
<!--{- render_command_arg_lists(standard_module_commands) }-->
|
||||
|
||||
<list name="variables">
|
||||
<!--[- for var in variables.kw ]-->
|
||||
<item><!--{var}--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<list name="deprecated-or-internal-variables">
|
||||
<!--[- for var in deprecated_or_internal_variables.kw ]-->
|
||||
<item><!--{var}--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<list name="environment-variables">
|
||||
<!--[- for var in environment_variables.kw ]-->
|
||||
<item><!--{var}--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<!--[- for kind in properties.kinds ]-->
|
||||
<list name="<!--{ kind|replace('_', '-') }-->">
|
||||
<!--[- for prop in properties[kind].kw ]-->
|
||||
<item><!--{prop}--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
<!--[- endfor ]-->
|
||||
|
||||
<list name="generator-expressions">
|
||||
<!--[- for expr in generator_expressions ]-->
|
||||
<item><!--{ expr }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
<!--[- for expr in complex_generator_expressions ]-->
|
||||
<list name="genex-<!--{expr.name}-->-subcommands">
|
||||
<!--[- for cmd in expr.subcommands ]-->
|
||||
<item><!--{ cmd }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
<!--[- endfor ]-->
|
||||
|
||||
<list name="standard-modules">
|
||||
<!--[- for module in modules.utility ]-->
|
||||
<item><!--{ module }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<list name="standard-finder-modules">
|
||||
<!--[- for module in modules.finder ]-->
|
||||
<item><!--{ module | replace('Find', '') }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<list name="deprecated-modules">
|
||||
<!--[- for module in modules.deprecated ]-->
|
||||
<item><!--{ module }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<!-- Source/cmStringAlgorithms.cxx: bool cmIsOff(cm::string_view val) -->
|
||||
<list name="true_special_arg">
|
||||
<item>TRUE</item>
|
||||
<item>ON</item>
|
||||
<item>YES</item>
|
||||
<item>Y</item>
|
||||
<item>0</item>
|
||||
</list>
|
||||
|
||||
<!-- Source/cmStringAlgorithms.cxx: bool cmIsOff(cm::string_view val) -->
|
||||
<list name="false_special_arg">
|
||||
<item>FALSE</item>
|
||||
<item>OFF</item>
|
||||
<item>NO</item>
|
||||
<item>IGNORE</item>
|
||||
<item>N</item>
|
||||
<item>0</item>
|
||||
</list>
|
||||
|
||||
<contexts>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Normal Text">
|
||||
<DetectSpaces />
|
||||
<!--[ for command in commands -]-->
|
||||
<WordDetect String="<!--{command.name}-->" insensitive="true" attribute="<!--{command.attribute}-->" context="<!--{command.name}-->_ctx"<!--[ if command.start_region ]--> beginRegion="<!--{command.start_region}-->"<!--[ endif -]--> <!--[- if command.end_region ]--> endRegion="<!--{command.end_region}-->"<!--[ endif ]--> />
|
||||
<!--[ endfor -]-->
|
||||
<!--[ for command in standard_module_commands -]-->
|
||||
<WordDetect String="<!--{command.name}-->" insensitive="true" attribute="CMake Provided Function/Macro" context="<!--{command.name}-->_ctx" />
|
||||
<!--[ endfor -]-->
|
||||
<DetectChar attribute="Comment" context="Match Comments and Docs" char="#" lookAhead="true" />
|
||||
<DetectIdentifier attribute="User Function/Macro" context="User Function" />
|
||||
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&var_ref_re;@" lookAhead="true" />
|
||||
<IncludeRules context="LineError" />
|
||||
</context>
|
||||
<!--[- macro render_command_parsers(commands) ]-->
|
||||
<!--[ for command in commands -]-->
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx">
|
||||
<DetectChar attribute="Normal Text" context="<!--{command.name}-->_ctx_op<!--{'_tgt_first' if command.first_arg_is_target else '_tgts_first' if command.first_args_are_targets else ''}-->" char="(" />
|
||||
<DetectChar attribute="Normal Text" context="#pop" char=")" />
|
||||
</context>
|
||||
<!--[- if command.first_arg_is_target ]-->
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op_tgt_first">
|
||||
<DetectSpaces />
|
||||
<RegExpr attribute="Aliased Targets" context="<!--{command.name}-->_ctx_op" String="&tgt_name_re;::&tgt_name_re;(?:\:\:&tgt_name_re;)*" />
|
||||
<RegExpr attribute="Targets" context="<!--{command.name}-->_ctx_op" String="&tgt_name_re;" />
|
||||
<IncludeRules context="User Function Opened" />
|
||||
<IncludeRules context="LineError" />
|
||||
</context>
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.first_args_are_targets ]-->
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op_tgts_first">
|
||||
<DetectSpaces />
|
||||
<!--[- if command.named_args and command.named_args.kw ]-->
|
||||
<!-- NOTE Handle the only case in CMake nowadays:
|
||||
1. `set_target_properties` have a named keyword (`PROPERTIES`) after targets list
|
||||
-->
|
||||
<keyword context="<!--{command.name}-->_ctx_op" String="<!--{command.name}-->_nargs" lookAhead="true" />
|
||||
<!--[- endif ]-->
|
||||
<IncludeRules context="Detect Aliased Targets" />
|
||||
<IncludeRules context="Detect Targets" />
|
||||
<IncludeRules context="User Function Opened" />
|
||||
<IncludeRules context="LineError" />
|
||||
</context>
|
||||
<!--[- endif ]-->
|
||||
<!--[- if not command.first_args_are_targets or (command.named_args and command.named_args.kw) ]-->
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op">
|
||||
<DetectSpaces />
|
||||
<!--[- if command.nested_parentheses ]-->
|
||||
<DetectChar attribute="Normal Text" context="<!--{command.name}-->_ctx_op_nested" char="(" />
|
||||
<!--[- endif ]-->
|
||||
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||
<!--[- if command.named_args and command.named_args.kw ]-->
|
||||
<!--[- if command.has_target_name_after_kw ]-->
|
||||
<WordDetect String="<!--{command.has_target_name_after_kw}-->" attribute="Named Args" context="Target Name" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.has_target_names_after_kw ]-->
|
||||
<!--[- for kw in command.has_target_names_after_kw ]-->
|
||||
<WordDetect String="<!--{kw}-->" attribute="Named Args" context="<!--{command.name}-->_tgts" />
|
||||
<!--[- endfor ]-->
|
||||
<!--[- endif ]-->
|
||||
<keyword attribute="Named Args" context="#stay" String="<!--{command.name}-->_nargs" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.name == 'include' ]-->
|
||||
<keyword attribute="Standard Module" context="#stay" String="standard-modules" />
|
||||
<keyword attribute="Deprecated Module" context="#stay" String="deprecated-modules" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.name == 'find_package' ]-->
|
||||
<keyword attribute="Standard Module" context="#stay" String="standard-finder-modules" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.special_args and command.special_args.kw ]-->
|
||||
<keyword attribute="Special Args" context="#stay" String="<!--{command.name}-->_sargs" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.property_args and command.property_args.kw ]-->
|
||||
<!--[- for kind in command.property_args.kw ]-->
|
||||
<keyword attribute="Property" context="#stay" String="<!--{kind}-->" />
|
||||
<!--[- if properties[kind|replace('-', '_')].re ]-->
|
||||
<IncludeRules context="Detect More <!--{kind}-->" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- endfor ]-->
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command is not nulary ]-->
|
||||
<IncludeRules context="User Function Args" />
|
||||
<!--[- if command.name == 'cmake_policy' ]-->
|
||||
<!-- NOTE Handle CMP<NNN> as a special arg of `cmake_policy` command -->
|
||||
<RegExpr attribute="Special Args" context="#stay" String="\bCMP[0-9]+\b" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- endif ]-->
|
||||
</context>
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.has_target_names_after_kw ]-->
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_tgts">
|
||||
<DetectSpaces />
|
||||
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||
<keyword attribute="Named Args" context="#pop" String="<!--{command.name}-->_nargs" lookAhead="true" />
|
||||
<IncludeRules context="Detect Aliased Targets" />
|
||||
<IncludeRules context="Detect Targets" />
|
||||
<IncludeRules context="User Function Args" />
|
||||
<IncludeRules context="LineError" />
|
||||
</context>
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.nested_parentheses ]-->
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op_nested">
|
||||
<DetectSpaces />
|
||||
<DetectChar attribute="Normal Text" context="#pop" char=")" />
|
||||
<DetectChar attribute="Normal Text" context="<!--{command.name}-->_ctx_op_nested" char="(" />
|
||||
<!--[- if command.named_args and command.named_args.kw ]-->
|
||||
<keyword attribute="Named Args" context="#stay" String="<!--{command.name}-->_nargs" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.special_args and command.special_args.kw ]-->
|
||||
<keyword attribute="Special Args" context="#stay" String="<!--{command.name}-->_sargs" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if command.property_args and command.property_args.kw ]-->
|
||||
<!--[- for kind in command.property_args.kw ]-->
|
||||
<keyword attribute="Property" context="#stay" String="<!--{kind}-->" />
|
||||
<!--[- if properties[kind|replace('-', '_')].re ]-->
|
||||
<IncludeRules context="Detect More <!--{kind}-->" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- endfor ]-->
|
||||
<!--[- endif ]-->
|
||||
<IncludeRules context="User Function Args" />
|
||||
</context>
|
||||
<!--[- endif ]-->
|
||||
<!--[ endfor -]-->
|
||||
<!--[- endmacro -]-->
|
||||
<!--{- render_command_parsers(commands) -}-->
|
||||
<!--{- render_command_parsers(standard_module_commands) -}-->
|
||||
<!--[ for kind in properties.kinds if properties[kind].re -]-->
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More <!--{ kind|replace('_', '-') }-->">
|
||||
<RegExpr attribute="Property" context="#stay" String="<!--{properties[kind].re}-->" />
|
||||
</context><!--{ '\n' }-->
|
||||
<!--[ endfor -]-->
|
||||
|
||||
<context attribute="User Function/Macro" lineEndContext="#stay" name="User Function">
|
||||
<DetectChar attribute="Normal Text" context="User Function Opened" char="(" />
|
||||
<DetectChar attribute="Normal Text" context="#pop" char=")" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="User Function Opened">
|
||||
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||
<IncludeRules context="User Function Args" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Builtin Variables">
|
||||
<RegExpr attribute="Internal Name" context="#stay" String="\b_&var_ref_re;\b" />
|
||||
<keyword attribute="CMake Internal Variable" context="#stay" String="deprecated-or-internal-variables" insensitive="false" />
|
||||
<keyword attribute="Builtin Variable" context="#stay" String="variables" insensitive="false" />
|
||||
<IncludeRules context="Detect More Builtin Variables" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More Builtin Variables">
|
||||
<!--[- if deprecated_or_internal_variables.re ]-->
|
||||
<RegExpr attribute="CMake Internal Variable" context="#stay" String="<!--{deprecated_or_internal_variables.re}-->" />
|
||||
<!--[- endif ]-->
|
||||
<!--[- if variables.re ]-->
|
||||
<RegExpr attribute="Builtin Variable" context="#stay" String="<!--{variables.re}-->" />
|
||||
<!--[- endif ]-->
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Variable Substitutions">
|
||||
<RegExpr attribute="Cache Variable Substitution" context="#stay" String="\$CACHE\{\s*[\w-]+\s*\}" />
|
||||
<RegExpr attribute="Environment Variable Substitution" context="EnvVarSubst" String="\$?ENV\{" />
|
||||
<Detect2Chars attribute="Variable Substitution" context="VarSubst" char="$" char1="{" />
|
||||
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&var_ref_re;@" lookAhead="true" />
|
||||
</context>
|
||||
|
||||
<context attribute="Environment Variable Substitution" lineEndContext="#pop" name="EnvVarSubst">
|
||||
<DetectChar attribute="Environment Variable Substitution" context="#pop" char="}" />
|
||||
<keyword attribute="Standard Environment Variable" context="#stay" String="environment-variables" insensitive="false" />
|
||||
<!--[- if environment_variables.re ]-->
|
||||
<RegExpr attribute="Standard Environment Variable" context="#stay" String="<!--{environment_variables.re}-->" />
|
||||
<!--[- endif ]-->
|
||||
<DetectIdentifier />
|
||||
<IncludeRules context="Detect Variable Substitutions" />
|
||||
</context>
|
||||
|
||||
<context attribute="Variable Substitution" lineEndContext="#pop" name="VarSubst">
|
||||
<DetectChar attribute="Variable Substitution" context="#pop" char="}" />
|
||||
<IncludeRules context="Detect Builtin Variables" />
|
||||
<DetectIdentifier />
|
||||
<IncludeRules context="Detect Variable Substitutions" />
|
||||
</context>
|
||||
|
||||
<context attribute="@Variable Substitution" lineEndContext="#pop" name="@VarSubst">
|
||||
<DetectChar attribute="@Variable Substitution" context="VarSubst@" char="@" />
|
||||
</context>
|
||||
|
||||
<context attribute="@Variable Substitution" lineEndContext="#pop#pop" name="VarSubst@">
|
||||
<DetectChar attribute="@Variable Substitution" context="#pop#pop" char="@" />
|
||||
<IncludeRules context="Detect Builtin Variables" />
|
||||
<DetectIdentifier />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Target Name">
|
||||
<DetectSpaces />
|
||||
<RegExpr attribute="Aliased Targets" context="#pop" String="&tgt_name_re;::&tgt_name_re;(?:\:\:&tgt_name_re;)*" />
|
||||
<IncludeRules context="Detect Targets" />
|
||||
<IncludeRules context="User Function Opened" />
|
||||
<IncludeRules context="LineError" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Targets">
|
||||
<RegExpr attribute="Targets" context="#stay" String="&tgt_name_re;" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="LineError">
|
||||
<RegExpr attribute="Error" context="#stay" String=".*" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="User Function Args">
|
||||
<Detect2Chars attribute="Normal Text" context="#stay" char="\" char1="(" />
|
||||
<Detect2Chars attribute="Normal Text" context="#stay" char="\" char1=")" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1=""" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="$" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="n" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="\" />
|
||||
<DetectChar attribute="Strings" context="String" char=""" />
|
||||
<RegExpr attribute="Strings" context="Bracketed String" String="\[(=*)\[" beginRegion="BracketedString" />
|
||||
<DetectChar attribute="Comment" context="Match Comments" char="#" lookAhead="true" />
|
||||
<IncludeRules context="Detect Builtin Variables" />
|
||||
<IncludeRules context="Detect Variable Substitutions" />
|
||||
<IncludeRules context="Detect Special Values" />
|
||||
<IncludeRules context="Detect Aliased Targets" />
|
||||
<IncludeRules context="Detect Generator Expressions" />
|
||||
<DetectIdentifier />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Special Values">
|
||||
<RegExpr attribute="Version Arg" context="#stay" String="\b[0-9]++(.[0-9]++)+\b" />
|
||||
<keyword attribute="True Special Arg" context="#stay" String="true_special_arg" insensitive="true" />
|
||||
<keyword attribute="False Special Arg" context="#stay" String="false_special_arg" insensitive="true" />
|
||||
<RegExpr attribute="False Special Arg" context="#stay" String="\b(?:&var_ref_re;-)?NOTFOUND\b" />
|
||||
<RegExpr attribute="Special Args" context="#stay" String="\bCMP[0-9][0-9][0-9][0-9]\b" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Aliased Targets">
|
||||
<RegExpr attribute="Aliased Targets" context="#stay" String="&tgt_name_re;::&tgt_name_re;(?:\:\:&tgt_name_re;)*" />
|
||||
</context>
|
||||
|
||||
<context attribute="Comment" lineEndContext="#pop" name="Match Comments">
|
||||
<DetectSpaces />
|
||||
<RegExpr attribute="Comment" context="#pop!Bracketed Comment" String="#\[(=*)\[" beginRegion="BracketedComment" />
|
||||
<DetectChar attribute="Comment" context="#pop!Comment" char="#" />
|
||||
<DetectIdentifier />
|
||||
</context>
|
||||
|
||||
<context attribute="Comment" lineEndContext="#pop" name="Match Comments and Docs">
|
||||
<RegExpr attribute="Region Marker" context="#pop!RST Documentation" String="^#\[(=*)\[\.rst:" column="0" beginRegion="RSTDocumentation" />
|
||||
<IncludeRules context="Match Comments" />
|
||||
</context>
|
||||
|
||||
<context attribute="Comment" lineEndContext="#pop" name="Comment">
|
||||
<DetectSpaces />
|
||||
<LineContinue attribute="Comment" context="#pop" />
|
||||
<IncludeRules context="##Comments" />
|
||||
<DetectIdentifier />
|
||||
</context>
|
||||
|
||||
<context attribute="Comment" lineEndContext="#stay" name="RST Documentation" dynamic="true">
|
||||
<RegExpr attribute="Region Marker" context="#pop" String="^#?\]%1\]" dynamic="true" column="0" endRegion="RSTDocumentation" />
|
||||
<IncludeRules context="##reStructuredText" />
|
||||
</context>
|
||||
|
||||
<context attribute="Comment" lineEndContext="#stay" name="Bracketed Comment" dynamic="true">
|
||||
<LineContinue attribute="Comment" context="#stay" />
|
||||
<DetectSpaces />
|
||||
<StringDetect attribute="Comment" context="#pop" String="]%1]" dynamic="true" endRegion="BracketedComment" />
|
||||
<IncludeRules context="##Comments" />
|
||||
</context>
|
||||
|
||||
<context attribute="Strings" lineEndContext="#stay" name="String">
|
||||
<DetectSpaces />
|
||||
<DetectIdentifier />
|
||||
<RegExpr attribute="Strings" context="#pop" String=""(?=[ );]|$)" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1=""" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="$" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="n" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="r" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="t" />
|
||||
<Detect2Chars attribute="Escapes" context="#stay" char="\" char1="\" />
|
||||
<IncludeRules context="Detect Variable Substitutions" />
|
||||
<IncludeRules context="Detect Generator Expressions" />
|
||||
</context>
|
||||
|
||||
<context attribute="Strings" lineEndContext="#stay" name="Bracketed String" dynamic="true">
|
||||
<StringDetect attribute="Strings" context="#pop" String="]%1]" dynamic="true" endRegion="BracketedString" />
|
||||
</context>
|
||||
|
||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Generator Expressions">
|
||||
<Detect2Chars attribute="Generator Expression" context="Generator Expression" char="$" char1="<" />
|
||||
</context>
|
||||
|
||||
<context attribute="Generator Expression" lineEndContext="#stay" name="Generator Expression">
|
||||
<IncludeRules context="Detect Generator Expressions" />
|
||||
<DetectChar attribute="Comment" context="Comment" char="#" />
|
||||
<DetectChar attribute="Generator Expression" context="#pop" char=">" />
|
||||
<keyword attribute="Generator Expression Keyword" context="#stay" String="generator-expressions" insensitive="false" />
|
||||
<!--[- for expr in complex_generator_expressions ]-->
|
||||
<WordDetect String="<!--{expr.name}-->" attribute="Generator Expression Keyword" context="genex_<!--{expr.name}-->_ctx" />
|
||||
<!--[- endfor ]-->
|
||||
<IncludeRules context="Detect Aliased Targets" />
|
||||
<IncludeRules context="Detect Variable Substitutions" />
|
||||
<DetectIdentifier />
|
||||
</context>
|
||||
|
||||
<!--[- for expr in complex_generator_expressions ]-->
|
||||
<context attribute="Generator Expression" lineEndContext="#stay" name="genex_<!--{expr.name}-->_ctx" fallthroughContext="#pop">
|
||||
<DetectChar char=":" context="#stay" />
|
||||
<DetectSpaces />
|
||||
<keyword attribute="Generator Expression Sub-Command" context="#pop" String="genex-<!--{expr.name}-->-subcommands" insensitive="false" />
|
||||
</context>
|
||||
<!--[- endfor ]-->
|
||||
|
||||
</contexts>
|
||||
|
||||
<itemDatas>
|
||||
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false" />
|
||||
<itemData name="Comment" defStyleNum="dsComment" spellChecking="true" />
|
||||
<itemData name="Command" defStyleNum="dsKeyword" spellChecking="false" />
|
||||
<itemData name="Control Flow" defStyleNum="dsControlFlow" spellChecking="false" />
|
||||
<itemData name="CMake Provided Function/Macro" defStyleNum="dsFunction" bold="true" spellChecking="false" />
|
||||
<itemData name="User Function/Macro" defStyleNum="dsFunction" spellChecking="false" />
|
||||
<itemData name="Property" defStyleNum="dsOthers" spellChecking="false" />
|
||||
<itemData name="Targets" defStyleNum="dsBaseN" spellChecking="false" />
|
||||
<itemData name="Aliased Targets" defStyleNum="dsBaseN" spellChecking="false" />
|
||||
<itemData name="Named Args" defStyleNum="dsOthers" spellChecking="false" />
|
||||
<itemData name="Special Args" defStyleNum="dsOthers" spellChecking="false" />
|
||||
<itemData name="True Special Arg" defStyleNum="dsOthers" color="#30a030" selColor="#30a030" spellChecking="false" />
|
||||
<itemData name="False Special Arg" defStyleNum="dsOthers" color="#e05050" selColor="#e05050" spellChecking="false" />
|
||||
<itemData name="Version Arg" defStyleNum="dsDataType" spellChecking="false" />
|
||||
<itemData name="Strings" defStyleNum="dsString" spellChecking="true" />
|
||||
<itemData name="Escapes" defStyleNum="dsSpecialChar" spellChecking="false" />
|
||||
<itemData name="Builtin Variable" defStyleNum="dsDecVal" color="#c09050" selColor="#c09050" spellChecking="false" />
|
||||
<itemData name="CMake Internal Variable" defStyleNum="dsVariable" spellChecking="false" />
|
||||
<itemData name="Internal Name" defStyleNum="dsVariable" spellChecking="false" />
|
||||
<itemData name="Variable Substitution" defStyleNum="dsDecVal" spellChecking="false" />
|
||||
<itemData name="@Variable Substitution" defStyleNum="dsBaseN" spellChecking="false" />
|
||||
<itemData name="Cache Variable Substitution" defStyleNum="dsFloat" spellChecking="false" />
|
||||
<itemData name="Environment Variable Substitution" defStyleNum="dsFloat" spellChecking="false" />
|
||||
<itemData name="Standard Environment Variable" defStyleNum="dsFloat" spellChecking="false" />
|
||||
<itemData name="Generator Expression Keyword" defStyleNum="dsKeyword" color="#b84040" selColor="#b84040" spellChecking="false" />
|
||||
<itemData name="Generator Expression Sub-Command" defStyleNum="dsKeyword" color="#c05050" selColor="#c05050" spellChecking="false" />
|
||||
<itemData name="Generator Expression" defStyleNum="dsOthers" color="#b86050" selColor="#b86050" spellChecking="false" />
|
||||
<itemData name="Standard Module" defStyleNum="dsImport" spellChecking="false" />
|
||||
<itemData name="Deprecated Module" defStyleNum="dsImport" spellChecking="false" />
|
||||
<itemData name="Region Marker" defStyleNum="dsRegionMarker" spellChecking="false" />
|
||||
<itemData name="Error" defStyleNum="dsError" spellChecking="false" />
|
||||
</itemDatas>
|
||||
|
||||
</highlighting>
|
||||
|
||||
<general>
|
||||
<comments>
|
||||
<comment name="singleLine" start="#" position="afterwhitespace" />
|
||||
<comment name="multiLine" start="#[[" end="]]" region="BracketedComment" />
|
||||
</comments>
|
||||
<keywords casesensitive="1" weakDeliminator="." />
|
||||
</general>
|
||||
</language>
|
||||
|
||||
<!-- kate: replace-tabs on; indent-width 2; tab-width 2; -->
|
||||
File diff suppressed because it is too large
Load Diff
+516
@@ -0,0 +1,516 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Generate Kate syntax file for CMake
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2017-2024 Alex Turbov <i.zaufi@gmail.com>
|
||||
#
|
||||
# To install prerequisites:
|
||||
#
|
||||
# $ pip install --user click jinja2 lxml pyyaml
|
||||
#
|
||||
# To use:
|
||||
#
|
||||
# $ ./generate-cmake-syntax.py cmake.yaml > ../syntax/cmake.xml
|
||||
#
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
import click
|
||||
import jinja2
|
||||
import yaml
|
||||
import sys
|
||||
from lxml import etree
|
||||
|
||||
|
||||
_TEMPLATED_NAME = re.compile(r'(?:<[^>]+>)')
|
||||
_PROPERTY_KEYS = [
|
||||
'global-properties'
|
||||
, 'directory-properties'
|
||||
, 'target-properties'
|
||||
, 'source-properties'
|
||||
, 'test-properties'
|
||||
, 'cache-properties'
|
||||
, 'install-properties'
|
||||
]
|
||||
_KW_RE_LIST = ['kw', 're']
|
||||
_VAR_KIND_LIST = ['variables', 'deprecated-or-internal-variables', 'environment-variables']
|
||||
_CONTROL_FLOW_LIST = {
|
||||
'break'
|
||||
, 'continue'
|
||||
, 'elseif'
|
||||
, 'else'
|
||||
, 'endforeach'
|
||||
, 'endif'
|
||||
, 'endwhile'
|
||||
, 'foreach'
|
||||
, 'if'
|
||||
, 'return'
|
||||
, 'while'
|
||||
}
|
||||
_VAR_REF_ENTITY = '&var_ref_re;'
|
||||
|
||||
_HEURISTICS = [
|
||||
(
|
||||
{'MAX(_(COUNT|MAJOR|MINOR|PATCH|TWEAK))?', 'MIN(_(COUNT|MAJOR|MINOR|PATCH|TWEAK))?'}
|
||||
, 'M(AX|IN)(_(COUNT|MAJOR|MINOR|PATCH|TWEAK))?'
|
||||
)
|
||||
, ({'OUTPUTS', 'OUTPUT_(HEADER|SOURCE)'}, 'OUTPUT(S|_(HEADER|SOURCE))')
|
||||
, ({'PREFIX', 'SUFFIX'}, '(PRE|SUF)FIX')
|
||||
, ({'CPPCHECK', 'CPPLINT'}, 'CPP(CHECK|LINT)')
|
||||
, ({'DEPENDS', 'PREDEPENDS'}, '(PRE)?DEPENDS')
|
||||
, ({'ICON', 'ICONURL'}, 'ICON(URL)?')
|
||||
, (
|
||||
{
|
||||
'&var%ref%re;(_INIT)?'
|
||||
, 'DEBUG(_INIT)?'
|
||||
, 'MINSIZEREL(_INIT)?'
|
||||
, 'RELEASE(_INIT)?'
|
||||
, 'RELWITHDEBINFO(_INIT)?'
|
||||
}
|
||||
, '(DEBUG|MINSIZEREL|REL(EASE|WITHDEBINFO)|&var%ref%re;)(_INIT)?'
|
||||
)
|
||||
, ({'RELEASE', 'RELWITHDEBINFO'}, 'REL(EASE|WITHDEBINFO)')
|
||||
, ({'POST', 'POSTUN', 'PRE', 'PREUN'}, 'P(RE|OST)(UN)?')
|
||||
, ({'AUTOPROV', 'AUTOREQ', 'AUTOREQPROV'}, 'AUTO(PROV|REQ(PROV)?)')
|
||||
, ({'DEFINITIONS', 'OPTIONS'}, '(DEFINI|OP)TIONS')
|
||||
, ({'LIB_NAMES', 'LIBRARY'}, 'LIB(_NAMES|RARY)')
|
||||
, ({'EXTENSIONS', 'EXTRA_FLAGS'}, 'EXT(ENSIONS|RA_FLAGS)')
|
||||
, ({'DISABLED', 'DISPLAY_NAME'}, 'DIS(ABLED|PLAY_NAME)')
|
||||
, ({'LIBRARIES', 'LINK_LIBRARIES', 'STATIC_LINK_LIBRARIES'}, '((STATIC_)?LINK_)?LIBRARIES')
|
||||
, ({'INCLUDE_DIRS', 'LIBRARY_DIRS'}, '(INCLUDE|LIBRARY)_DIRS')
|
||||
, ({'BINARY_DIR', 'SOURCE_DIR'}, '(BINARY|SOURCE)_DIR')
|
||||
, ({'CFLAGS(_OTHER)?', 'LDFLAGS(_OTHER)?'}, '(C|LD)FLAGS(_OTHER)?')
|
||||
, ({'INCLUDE_DIRECTORIES', 'LIBRARIES'}, '(INCLUDE_DIRECTO|LIBRA)RIES')
|
||||
, ({'POSTFLIGHT_&var%ref%re;_SCRIPT', 'PREFLIGHT_&var%ref%re;_SCRIPT'}, 'P(RE|OST)FLIGHT_&var%ref%re;_SCRIPT')
|
||||
, ({'DIRECTORIES', 'FRAMEWORK_DIRECTORIES'}, '(FRAMEWORK_)?DIRECTORIES')
|
||||
, ({'FILE_FLAG', 'FILE'}, 'FILE(_FLAG)?')
|
||||
, ({'DIR_PERMISSIONS', 'FILE_PERMISSIONS'}, '(DIR|FILE)_PERMISSIONS')
|
||||
, ({'COMPILER_LAUNCHER', 'LINKER_LAUNCHER'}, '(COMPIL|LINK)ER_LAUNCHER')
|
||||
, ({'COMPILER', 'COMPILE_(DEFINI|OP)TIONS'}, 'COMPILE(R|_(DEFINI|OP)TIONS)')
|
||||
, ({'LICENSEURL', 'LICENSE_(EXPRESSION|FILE_NAME)'}, 'LICENSE(URL|_(EXPRESSION|FILE_NAME))')
|
||||
, ({'NO_SONAME', 'SONAME'}, '(NO_)?SONAME')
|
||||
, ({'CODE_SIGN_ON_COPY', 'REMOVE_HEADERS_ON_COPY'}, '(CODE_SIGN|REMOVE_HEADERS)_ON_COPY')
|
||||
, ({'(REFERENCE|REFERENCEPROP_&var%ref%re;_TAG)_&var%ref%re;'}, 'REFERENCE(PROP_&var%ref%re;_TAG)?_&var%ref%re;')
|
||||
, ({'DISABLE_FIND_PACKAGE', 'REQUIRE_FIND_PACKAGE'}, '(DISABLE|REQUIRE)_FIND_PACKAGE')
|
||||
, (
|
||||
{'GROUP_USING_&var%ref%re;(_SUPPORTED)?', 'LIBRARY_USING_&var%ref%re;(_SUPPORTED)?'}
|
||||
, '(GROUP|LIBRARY)_USING_&var%ref%re;(_SUPPORTED)?'
|
||||
)
|
||||
, (
|
||||
{
|
||||
'EXE_LINKER_FLAGS_&var%ref%re;(_INIT)?'
|
||||
, 'MODULE_LINKER_FLAGS_&var%ref%re;(_INIT)?'
|
||||
, 'SHARED_LINKER_FLAGS_&var%ref%re;(_INIT)?'
|
||||
, 'STATIC_LINKER_FLAGS_&var%ref%re;(_INIT)?'
|
||||
}
|
||||
, '(EXE|MODULE|SHARED|STATIC)_LINKER_FLAGS_&var%ref%re;(_INIT)?'
|
||||
)
|
||||
, (
|
||||
{
|
||||
'ARCHIVE_OUTPUT_DIRECTORY'
|
||||
, 'COMPILE_PDB_OUTPUT_DIRECTORY'
|
||||
, 'LIBRARY_OUTPUT_DIRECTORY'
|
||||
, 'PDB_OUTPUT_DIRECTORY'
|
||||
, 'RUNTIME_OUTPUT_DIRECTORY'
|
||||
}
|
||||
, '(ARCHIVE|(COMPILE_)?PDB|LIBRARY|RUNTIME)_OUTPUT_DIRECTORY'
|
||||
)
|
||||
, (
|
||||
{
|
||||
'ARCHIVE_OUTPUT_(DIRECTORY|NAME)'
|
||||
, 'LIBRARY_OUTPUT_(DIRECTORY|NAME)'
|
||||
, 'RUNTIME_OUTPUT_(DIRECTORY|NAME)'
|
||||
}
|
||||
, '(ARCHIVE|LIBRARY|RUNTIME)_OUTPUT_(DIRECTORY|NAME)'
|
||||
)
|
||||
, ({'ASM&var_ref_re;', 'ASM&var_ref_re;FLAGS'}, 'ASM&var_ref_re;(FLAGS)?')
|
||||
, (
|
||||
{
|
||||
'CMAKE_POLICY_DEFAULT_CMP[0-9]{4}'
|
||||
, 'CMAKE_POLICY_WARNING_CMP[0-9]{4}'
|
||||
}
|
||||
, 'CMAKE_POLICY_(DEFAULT|WARNING)_CMP[0-9]{4}'
|
||||
)
|
||||
, ({'CMAKE_ARGV[0-9]+', 'CMAKE_MATCH_[0-9]+'}, 'CMAKE_(ARGV|MATCH_)[0-9]+')
|
||||
]
|
||||
|
||||
@dataclass
|
||||
class RePartNode:
|
||||
children: dict[str, RePartNode] = field(default_factory=dict, hash=False)
|
||||
is_leaf: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class RegexCollection:
|
||||
special_cases: list[str] = field(default_factory=list, hash=False)
|
||||
re_tree: dict[str, RePartNode] = field(default_factory=dict, hash=False)
|
||||
|
||||
def add_case(self, regex: str) -> RegexCollection:
|
||||
self.special_cases.append(regex)
|
||||
return self
|
||||
|
||||
def update_tree(self, name_parts: list[str]) -> RegexCollection:
|
||||
safe_var_ref = _VAR_REF_ENTITY.replace('_', '%')
|
||||
functools.reduce(
|
||||
lambda current, part: (
|
||||
self.re_tree if current is None else current.children
|
||||
).setdefault(part, RePartNode())
|
||||
, (
|
||||
safe_var_ref
|
||||
.join(name_parts)
|
||||
.replace(f'{safe_var_ref}_{safe_var_ref}', safe_var_ref)
|
||||
.split('_')
|
||||
)
|
||||
, None
|
||||
).is_leaf = True
|
||||
return self
|
||||
|
||||
|
||||
def try_transform_placeholder_string_to_regex(state: RegexCollection, name: str):
|
||||
'''
|
||||
NOTE Some placeholders are not IDs, but numbers...
|
||||
`CMAKE_MATCH_<N>` 4 example
|
||||
'''
|
||||
name_parts = _TEMPLATED_NAME.split(name)
|
||||
match name_parts:
|
||||
case ['CMAKE_MATCH_' as head, ''] | ['CMAKE_ARGV' as head, ''] | ['ARGV' as head, '']:
|
||||
return state.add_case(head + '[0-9]+')
|
||||
|
||||
case ['CMAKE_POLICY_DEFAULT_CMP' as head, ''] | ['CMAKE_POLICY_WARNING_CMP' as head, '']:
|
||||
return state.add_case(head + '[0-9]{4}')
|
||||
|
||||
case ['', '__TRYRUN_OUTPUT']:
|
||||
return state.add_case(f'{_VAR_REF_ENTITY}__TRYRUN_OUTPUT')
|
||||
|
||||
case (['ASM', ''] | ['ASM', 'FLAGS']) as asm_env:
|
||||
return state.add_case(f'{asm_env[0]}{_VAR_REF_ENTITY}{asm_env[1]}')
|
||||
|
||||
return state.update_tree(name_parts)
|
||||
|
||||
|
||||
def is_first_subset_of_second(first, second):
|
||||
subset = set(first)
|
||||
fullset = set(second)
|
||||
return subset.issubset(fullset)
|
||||
|
||||
|
||||
def try_optimize_known_alt_groups(groups: list[str]) -> list[str]:
|
||||
for case in _HEURISTICS:
|
||||
if is_first_subset_of_second(case[0], groups):
|
||||
groups = sorted([*filter(lambda item: item not in case[0], groups), case[1]])
|
||||
return groups
|
||||
|
||||
|
||||
def try_optimize_trailing_var_ref_regex(groups: list[str]) -> list[str]:
|
||||
tail_var_ref_re = '_' + _VAR_REF_ENTITY.replace('_', '%')
|
||||
candidates = [*filter(lambda s: s.endswith(tail_var_ref_re), groups)]
|
||||
return sorted([
|
||||
*filter(lambda item: item not in candidates, groups)
|
||||
, f'({"|".join(try_optimize_known_alt_groups([s[:-len(tail_var_ref_re)] for s in candidates]))}){tail_var_ref_re}'
|
||||
]) if len(candidates) > 1 else groups
|
||||
|
||||
|
||||
def build_regex(state: list[str], kv: tuple[str, RePartNode]) -> list[str]:
|
||||
name, value = kv
|
||||
match (value, len(value.children)):
|
||||
case (RePartNode(children={}, is_leaf=True), 0):
|
||||
return [*state, name]
|
||||
|
||||
case (node, sz) if sz > 0:
|
||||
alt_group = try_optimize_known_alt_groups(
|
||||
try_optimize_trailing_var_ref_regex(
|
||||
functools.reduce(build_regex, node.children.items(), [])
|
||||
)
|
||||
)
|
||||
|
||||
match (len(alt_group), node.is_leaf):
|
||||
case (1, False):
|
||||
return [*state, f'{name}_{alt_group[0]}']
|
||||
|
||||
case (1, True):
|
||||
return [*state, f'{name}(_{alt_group[0]})?']
|
||||
|
||||
case (sz, False) if sz > 0:
|
||||
return [*state, f'{name}_({"|".join(alt_group)})']
|
||||
|
||||
case (sz, True) if sz > 0:
|
||||
return [*state, f'{name}(_({"|".join(alt_group)}))?']
|
||||
|
||||
case _:
|
||||
raise AssertionError('Zero children?')
|
||||
|
||||
case _:
|
||||
raise AssertionError(f'NOT MATCHED: {name=}→{value=}')
|
||||
|
||||
return state
|
||||
|
||||
|
||||
def try_placeholders_to_regex(names):
|
||||
if not names:
|
||||
return None
|
||||
|
||||
data = functools.reduce(
|
||||
try_transform_placeholder_string_to_regex
|
||||
, names
|
||||
, RegexCollection()
|
||||
)
|
||||
|
||||
return (
|
||||
'\\b(?:'
|
||||
+ '|'.join(
|
||||
try_optimize_known_alt_groups(
|
||||
try_optimize_trailing_var_ref_regex(
|
||||
functools.reduce(
|
||||
build_regex
|
||||
, data.re_tree.items()
|
||||
, data.special_cases
|
||||
)
|
||||
)
|
||||
)
|
||||
).replace('%', '_')
|
||||
+ ')\\b'
|
||||
)
|
||||
|
||||
|
||||
def partition_iterable(fn, iterable):
|
||||
true, false = [], []
|
||||
for i in iterable:
|
||||
(false, true)[int(fn(i))].append(i)
|
||||
return true, false
|
||||
|
||||
|
||||
def _transform_command_set(cmd, list_name):
|
||||
args, args_re = partition_iterable(lambda x: _TEMPLATED_NAME.search(x) is None, cmd[list_name])
|
||||
del cmd[list_name]
|
||||
list_name = list_name.replace('-', '_')
|
||||
|
||||
cmd[list_name] = {k: sorted(set(v)) for k, v in zip(_KW_RE_LIST, [args, args_re])}
|
||||
cmd[list_name]['re'] = try_placeholders_to_regex(args_re)
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
def transform_command(cmd):
|
||||
can_be_nulary = True
|
||||
|
||||
if 'name' not in cmd:
|
||||
raise RuntimeError('Command have no name')
|
||||
|
||||
if 'named-args' in cmd:
|
||||
new_cmd = _transform_command_set(cmd, 'named-args')
|
||||
assert new_cmd == cmd
|
||||
can_be_nulary = False
|
||||
|
||||
if 'special-args' in cmd:
|
||||
new_cmd = _transform_command_set(cmd, 'special-args')
|
||||
assert new_cmd == cmd
|
||||
can_be_nulary = False
|
||||
|
||||
if 'property-args' in cmd:
|
||||
new_cmd = _transform_command_set(cmd, 'property-args')
|
||||
assert new_cmd == cmd
|
||||
can_be_nulary = False
|
||||
|
||||
cmd['nested_parentheses'] = cmd.get('nested-parentheses?', False)
|
||||
|
||||
if 'first-arg-is-target?' in cmd:
|
||||
cmd['first_arg_is_target'] = cmd['first-arg-is-target?']
|
||||
can_be_nulary = False
|
||||
|
||||
if 'first-args-are-targets?' in cmd:
|
||||
cmd['first_args_are_targets'] = cmd['first-args-are-targets?']
|
||||
can_be_nulary = False
|
||||
|
||||
if 'has-target-name-after-kw' in cmd:
|
||||
cmd['has_target_name_after_kw'] = cmd['has-target-name-after-kw']
|
||||
can_be_nulary = False
|
||||
|
||||
if 'has-target-names-after-kw' in cmd:
|
||||
match cmd['has-target-names-after-kw']:
|
||||
case str():
|
||||
cmd['has_target_names_after_kw'] = [cmd['has-target-names-after-kw']]
|
||||
case list():
|
||||
cmd['has_target_names_after_kw'] = cmd['has-target-names-after-kw']
|
||||
case _:
|
||||
raise TypeError('Unexpected type for `has-target-names-after-kw`')
|
||||
can_be_nulary = False
|
||||
|
||||
if 'second-arg-is-target?' in cmd:
|
||||
cmd['second_arg_is_target'] = cmd['second-arg-is-target?']
|
||||
can_be_nulary = False
|
||||
|
||||
if 'nulary?' in cmd and cmd['nulary?'] and not can_be_nulary:
|
||||
raise RuntimeError('Command `{}` w/ args declared nulary!?'.format(cmd['name']))
|
||||
|
||||
if 'start-region' in cmd:
|
||||
cmd['start_region'] = cmd['start-region']
|
||||
|
||||
if 'end-region' in cmd:
|
||||
cmd['end_region'] = cmd['end-region']
|
||||
|
||||
cmd['attribute'] = 'Control Flow' if cmd['name'] in _CONTROL_FLOW_LIST else 'Command'
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
def remove_duplicate_list_nodes(root):
|
||||
remap = {}
|
||||
items_by_kws = {}
|
||||
|
||||
# extract duplicate keyword list
|
||||
for items in root.iterfind('highlighting/list'):
|
||||
key = '<'.join(item.text for item in items)
|
||||
name = items.attrib['name']
|
||||
if rename := items_by_kws.get(key):
|
||||
remap[name] = rename
|
||||
items.getparent().remove(items)
|
||||
else:
|
||||
items_by_kws[key] = name
|
||||
|
||||
# update keyword list name referenced by each rule
|
||||
for rule in root.iterfind('highlighting/contexts/context/keyword'):
|
||||
name = rule.attrib['String']
|
||||
rule.attrib['String'] = remap.get(name, name)
|
||||
|
||||
|
||||
def remove_duplicate_context_nodes(root):
|
||||
contexts = root[0].find('contexts')
|
||||
# 3 levels: ctx, ctx_op and ctx_op_nested
|
||||
# TODO Refactor it!
|
||||
for _ in range(3):
|
||||
remap = {}
|
||||
duplicated = {}
|
||||
|
||||
# remove duplicate nodes
|
||||
for context in contexts:
|
||||
name = context.attrib['name']
|
||||
context.attrib['name'] = 'dummy'
|
||||
ref = duplicated.setdefault(etree.tostring(context), [])
|
||||
if ref:
|
||||
contexts.remove(context)
|
||||
else:
|
||||
context.attrib['name'] = name
|
||||
ref.append(name)
|
||||
remap[name] = ref[0]
|
||||
|
||||
# update context name referenced by each rule
|
||||
for context in contexts:
|
||||
for rule in context:
|
||||
ref = remap.get(rule.attrib.get('context'))
|
||||
if ref:
|
||||
rule.attrib['context'] = ref
|
||||
|
||||
|
||||
def remove_duplicate_nodes(xml_string):
|
||||
parser = etree.XMLParser(resolve_entities=False, collect_ids=False)
|
||||
root = etree.fromstring(xml_string.encode(), parser=parser)
|
||||
|
||||
remove_duplicate_list_nodes(root)
|
||||
remove_duplicate_context_nodes(root)
|
||||
|
||||
# reformat comments
|
||||
xml = etree.tostring(root)
|
||||
xml = re.sub(b'(?=[^\n ])<!--', b'\n<!--', xml)
|
||||
xml = re.sub(b'-->(?=[^ \n])', b'-->\n', xml)
|
||||
|
||||
# extract DOCTYPE removed by etree.fromstring and reformat <language>
|
||||
doctype = xml_string[:xml_string.find('<highlighting')]
|
||||
|
||||
# remove unformatted <language>
|
||||
xml = xml[xml.find(b'<highlighting'):]
|
||||
|
||||
# last comment removed by etree.fromstring
|
||||
last_comment = '\n<!-- kate: replace-tabs on; indent-width 2; tab-width 2; -->'
|
||||
|
||||
return f'{doctype}{xml.decode()}{last_comment}'
|
||||
|
||||
|
||||
# BEGIN Jinja filters
|
||||
|
||||
def cmd_is_nulary(cmd):
|
||||
return cmd.setdefault('nulary?', False)
|
||||
|
||||
# END Jinja filters
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument('input_yaml', type=click.File('r'))
|
||||
@click.argument('template', type=click.File('r'), default='./cmake.xml.tpl')
|
||||
def cli(input_yaml, template):
|
||||
data = yaml.load(input_yaml, Loader=yaml.BaseLoader)
|
||||
|
||||
# Partition `variables` and `environment-variables` lists into "pure" (key)words and regexes to match
|
||||
for var_key in _VAR_KIND_LIST:
|
||||
data[var_key] = {
|
||||
k: sorted(set(v)) for k, v in zip(
|
||||
_KW_RE_LIST
|
||||
, [*partition_iterable(lambda x: _TEMPLATED_NAME.search(x) is None, data[var_key])]
|
||||
)
|
||||
}
|
||||
data[var_key]['re'] = try_placeholders_to_regex(data[var_key]['re'])
|
||||
|
||||
# Transform properties and make all-properties list
|
||||
data['properties'] = {}
|
||||
for prop in _PROPERTY_KEYS:
|
||||
python_prop_list_name = prop.replace('-', '_')
|
||||
props, props_re = partition_iterable(lambda x: _TEMPLATED_NAME.search(x) is None, data[prop])
|
||||
del data[prop]
|
||||
|
||||
data['properties'][python_prop_list_name] = {
|
||||
k: sorted(set(v)) for k, v in zip(_KW_RE_LIST, [props, props_re])
|
||||
}
|
||||
data['properties'][python_prop_list_name]['re'] = try_placeholders_to_regex(props_re)
|
||||
|
||||
data['properties']['kinds'] = list(map(lambda name: name.replace('-', '_'), _PROPERTY_KEYS))
|
||||
|
||||
# Make all commands list
|
||||
data['commands'] = list(
|
||||
map(
|
||||
transform_command
|
||||
, data['scripting-commands'] + data['project-commands'] + data['ctest-commands']
|
||||
)
|
||||
)
|
||||
data['standard_module_commands'] = list(
|
||||
map(
|
||||
transform_command
|
||||
, data['standard-module-commands']
|
||||
)
|
||||
)
|
||||
del data['standard-module-commands']
|
||||
|
||||
# Fix node names to be accessible from Jinja template
|
||||
data['generator_expressions'] = (ex for ex in data['generator-expressions'] if isinstance(ex, str))
|
||||
data['complex_generator_expressions'] = [ex for ex in data['generator-expressions'] if not isinstance(ex, str)]
|
||||
data['deprecated_or_internal_variables'] = data['deprecated-or-internal-variables']
|
||||
data['environment_variables'] = data['environment-variables']
|
||||
del data['generator-expressions']
|
||||
del data['deprecated-or-internal-variables']
|
||||
del data['environment-variables']
|
||||
|
||||
env = jinja2.Environment(
|
||||
keep_trailing_newline=True
|
||||
)
|
||||
env.block_start_string = '<!--['
|
||||
env.block_end_string = ']-->'
|
||||
env.variable_start_string = '<!--{'
|
||||
env.variable_end_string = '}-->'
|
||||
env.comment_start_string = '<!--#'
|
||||
env.comment_end_string = '#-->'
|
||||
|
||||
# Register convenience filters
|
||||
env.tests['nulary'] = cmd_is_nulary
|
||||
|
||||
tpl = env.from_string(template.read())
|
||||
result = tpl.render(data)
|
||||
result = remove_duplicate_nodes(result)
|
||||
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
# TODO Handle execptions and show errors
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env perl
|
||||
# SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
my $file = "";
|
||||
|
||||
open(my $input, '<:encoding(UTF-8)', $ARGV[0])
|
||||
or die "Could not open file '$ARGV[0]': $!";
|
||||
|
||||
open(my $output, '>:encoding(UTF-8)', $ARGV[1])
|
||||
or die "Could not open file '$ARGV[1]': $!";
|
||||
|
||||
while (<$input>)
|
||||
{
|
||||
$file .= $_;
|
||||
}
|
||||
|
||||
$warning = "\n\n<!-- ***** THIS FILE WAS GENERATED BY A SCRIPT - DO NOT EDIT ***** -->\n";
|
||||
$first_context = " <context attribute=\"Normal Text\" lineEndContext=\"#stay\" name=\"Normal\">
|
||||
<RegExpr attribute=\"Comment\" context=\"LineComment\" String=\"--(?:!|(?:-(?=[^-]|\$)))\"/>
|
||||
<RegExpr attribute=\"Region\" context=\"#stay\" String=\"--\\s*\@\\{\\s*\$\" beginRegion=\"MemberGroup\" />
|
||||
<RegExpr attribute=\"Region\" context=\"#stay\" String=\"--\\s*\@\\}\\s*\$\" endRegion=\"MemberGroup\" />
|
||||
</context>";
|
||||
|
||||
$file =~ s/\n\s*<context [^\n]*?(?:name="ML_|name="BlockComment").*?<\/context>//gs;
|
||||
$file =~ s/\n\s*<context [^\n]*?name="Normal".*?<\/context>/\n$first_context/s;
|
||||
$file =~ s/\n[^\n]*?(?: ml_word|LineContinue)[^\n]+//gs;
|
||||
$file =~ s/\/\/\//---/gs;
|
||||
$file =~ s/\/\/!/--!/gs;
|
||||
|
||||
$language = $file =~ s/.*?(<language[^>]+?>).*/$1/sr;
|
||||
$language =~ s/ name="[^"]+/ name="DoxygenLua/s;
|
||||
$language =~ s/ extensions="[^"]+/ extensions="/s;
|
||||
$language =~ s/ mimetype="[^"]+/ mimetype="/s;
|
||||
$language =~ s/ priority="[^"]+"//s;
|
||||
$version = $language =~ s/.*? version="([^"]+).*/$1/sr;
|
||||
$version = $version+2;
|
||||
$language =~ s/ version="[^"]+/ version="$version/s;
|
||||
$file =~ s/<language[^>]+?>/$warning\n$language/s;
|
||||
|
||||
print $output $file;
|
||||
print $output $warning;
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# This perl script read stdin and write on stdout. It shall be an XML language file.
|
||||
#
|
||||
# * If the name of the language is 'HTML', then it creates the language 'PHP (HTML)'
|
||||
# which shall be used for PHP hl.
|
||||
#
|
||||
# * If the name of the language is something else (say '*'), it creates the language '*/PHP'.
|
||||
# This new language is the same as the old one, but is able to detect PHP everywhere.
|
||||
#
|
||||
# This script will correctly set extensions & mimetype, and will replace
|
||||
# <IncludeRules context="##*"> by <IncludeRules context="##*/PHP">
|
||||
#
|
||||
# Generated languages need a language named 'PHP/PHP', which shall take care of PHP hl itself
|
||||
# and which will be called every time something like <?php is encountred.
|
||||
#
|
||||
# This script also supports Twig and does the same as for PHP.
|
||||
#
|
||||
# SPDX-FileCopyrightText: Jan Villat <jan.villat@net2000.ch>
|
||||
# License: LGPL
|
||||
|
||||
my $file = "";
|
||||
|
||||
open(my $input, '<:encoding(UTF-8)', $ARGV[0])
|
||||
or die "Could not open file '$ARGV[0]': $!";
|
||||
|
||||
open(my $output, '>:encoding(UTF-8)', $ARGV[1])
|
||||
or die "Could not open file '$ARGV[1]': $!";
|
||||
|
||||
my $language = $ARGV[1];
|
||||
if ($language =~ /-php\.xml$/)
|
||||
{
|
||||
$language = "PHP";
|
||||
}
|
||||
else
|
||||
{
|
||||
$language = "Twig";
|
||||
}
|
||||
|
||||
while (<$input>)
|
||||
{
|
||||
$file .= $_;
|
||||
}
|
||||
|
||||
$warning = "\n\n<!-- ***** THIS FILE WAS GENERATED BY A SCRIPT - DO NOT EDIT ***** -->\n";
|
||||
|
||||
$file =~ s/(?=<language)/$warning\n\n\n/;
|
||||
|
||||
$file =~ /<language.*?name="([^"]+)"/;
|
||||
my $syntaxName = $1;
|
||||
|
||||
if ($syntaxName eq "HTML")
|
||||
{
|
||||
$root = 1;
|
||||
}
|
||||
|
||||
if ($language eq "Twig")
|
||||
{
|
||||
$file =~ s/<language([^>]+)priority="[^"]*"/<language$1/s;
|
||||
}
|
||||
|
||||
if ($root == 1)
|
||||
{
|
||||
$file =~ s/<language([^>]+)name="[^"]*"/<language$1name="$language (HTML)"/s;
|
||||
$file =~ s/<language([^>]+)section="[^"]*"/<language$1section="Scripts"/s;
|
||||
if ($language eq "PHP")
|
||||
{
|
||||
$file =~ s/<language([^>]+)extensions="[^"]*"/<language$1extensions="*.php;*.php3;*.wml;*.phtml;*.phtm;*.inc;*.ctp"/s;
|
||||
$file =~ s/<language([^>]+)mimetype="[^"]*"/<language$1mimetype="text\/x-php4-src;text\/x-php3-src;text\/vnd.wap.wml;application\/x-php"/s;
|
||||
$file =~ s/<language([^>]+)*/<language$1 indenter="cstyle"/s;
|
||||
}
|
||||
# Twig
|
||||
else
|
||||
{
|
||||
$file =~ s/<language([^>]+)extensions="[^"]*"/<language$1extensions="*.twig;*.html.twig;*.htm.twig"/s;
|
||||
$file =~ s/<language([^>]+)mimetype="[^"]*"/<language$1mimetype="text\/x-twig"/s;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$file =~ s/<language([^>]+)hidden="[^"]*"/<language$1/s;
|
||||
$file =~ s/<language([^>]+)section="[^"]*"/<language$1section="Other"/s;
|
||||
my $extra = " hidden=\"true\"";
|
||||
my $mimetype = "";
|
||||
my $extensions = "";
|
||||
if ($language eq "Twig")
|
||||
{
|
||||
$mimetype = "text/x-twig";
|
||||
if ($syntaxName eq "JavaScript")
|
||||
{
|
||||
$extra = " priority=\"1\"";
|
||||
$extensions = "*.js.twig;*.mjs.twig;*.cjs.twig";
|
||||
}
|
||||
elsif ($syntaxName eq "TypeScript")
|
||||
{
|
||||
$extra = " priority=\"1\"";
|
||||
$extensions = "*.ts.twig;*.mts.twig;*.cts.twig";
|
||||
}
|
||||
}
|
||||
$file =~ s/<language([^>]+)mimetype="[^"]*"/<language$1mimetype="$mimetype"/s;
|
||||
$file =~ s/<language([^>]+)name="([^"]*)"/<language$1name="$2\/$language"$extra/s;
|
||||
$file =~ s/<language([^>]+)alternativeNames="([^"]*)"/<language$1alternativeNames="$2\/$language"/s;
|
||||
$file =~ s/<language([^>]+)extensions="[^"]*"/<language$1extensions="$extensions"/s;
|
||||
}
|
||||
|
||||
# replace list with a include
|
||||
$file =~ s/<list name="([^"]+)">.*?<\/list>/<list name="$1"><include>$1##$syntaxName<\/include><\/list>/gs;
|
||||
|
||||
$file =~ s/<language([^>]+)kateversion="[^"]*"/<language$1kateversion="5.79"/s;
|
||||
$file =~ s/ fallthrough="(true|1)"//gs;
|
||||
|
||||
if ($language eq "Twig")
|
||||
{
|
||||
# remove Mustache syntax
|
||||
if ($root == 1)
|
||||
{
|
||||
$file =~ s/<context name="MustacheJS.*?<\/context>//gs;
|
||||
$file =~ s/<StringDetect attribute="Value" context="#pop#pop!MustacheJS" String="[^"]+[^\/]+\/>//gs;
|
||||
}
|
||||
}
|
||||
elsif ($root == 1 || $ARGV[0] =~ /mustache.xml$/)
|
||||
{
|
||||
$file =~ s/<(?:RegExpr (attribute="Processing Instruction" context="PI"|context="PI" attribute="Processing Instruction")|itemData name="Processing Instruction")[^\/]+\/>|<context name="PI".*?<\/context>//gs;
|
||||
}
|
||||
|
||||
my $find_language = "##$language/$language";
|
||||
my $language_suffix = "/$language";
|
||||
if ($language eq "PHP")
|
||||
{
|
||||
$find_language = "FindPHP";
|
||||
}
|
||||
|
||||
$file =~ s/<IncludeRules\s([^>]*)context="([^"#]*)##(?!Alerts|Comments|Doxygen|Modelines)([^"]+)"/<IncludeRules $1context="$2##$3$language_suffix"/g;
|
||||
$file =~ s/(<context\s[^>]*[^>\/]>)/$1\n<IncludeRules context="$find_language" \/>/g;
|
||||
$file =~ s/(<context\s[^>]*[^>\/])\s*\/>/$1>\n<IncludeRules context="$find_language" \/>\n<\/context>/g;
|
||||
|
||||
if ($language eq "PHP")
|
||||
{
|
||||
$findphp = "<context name=\"FindPHP\" attribute=\"Normal Text\" lineEndContext=\"#stay\">\n<Detect2Chars context=\"##PHP/PHP\" char=\"<\" char1=\"?\" lookAhead=\"true\" />\n</context>\n";
|
||||
$file =~ s/(?=<\/contexts\s*>)/$findphp/;
|
||||
}
|
||||
|
||||
print $output $file;
|
||||
print $output $warning;
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# Generates the keyword lists for directives and variables used in nginx and
|
||||
# prints them to stdout, ready to be copy & pasted into nginx.xml.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2023 Jyrki Gadinger <nilsding@nilsding.org>
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Usage:
|
||||
# % ./generate-nginx-lists.rb
|
||||
#
|
||||
# if you want to install the required dependencies provide `INSTALL_GEMS` in
|
||||
# your ENV:
|
||||
# % INSTALL_GEMS=1 ./generate-nginx-lists.rb
|
||||
|
||||
require "bundler/inline"
|
||||
|
||||
gemfile(ENV["INSTALL_GEMS"]) do
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "nokogiri", "~> 1.14"
|
||||
gem "faraday", "~> 2.7"
|
||||
gem "builder", "~> 3.2"
|
||||
end
|
||||
|
||||
def fetch_vars(url)
|
||||
Faraday.get(url)
|
||||
.then { Nokogiri::HTML.parse _1.body }
|
||||
.css("div#content a[href]")
|
||||
.map(&:text)
|
||||
.reject { _1.end_with?("_") } # some vars are just a prefix, ignore those
|
||||
.sort
|
||||
.uniq
|
||||
end
|
||||
|
||||
def build_xml_list(name, url: nil, items: [])
|
||||
builder = Builder::XmlMarkup.new(indent: 2)
|
||||
|
||||
builder.comment! "see #{url} for a full list of #{name}"
|
||||
builder.list(name:) do |b|
|
||||
items.each do |item|
|
||||
b.item item
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
{
|
||||
directives: "https://nginx.org/en/docs/dirindex.html",
|
||||
variables: "https://nginx.org/en/docs/varindex.html",
|
||||
}.each do |name, url|
|
||||
items = fetch_vars(url)
|
||||
|
||||
puts build_xml_list(name, url:, items:).gsub(/^/, ' ' * 4)
|
||||
puts
|
||||
end
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Generate SPDX-Comments syntax file
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020 Alex Turbov <i.zaufi@gmail.com>
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# To install prerequisites:
|
||||
#
|
||||
# $ pip install --user click jinja2
|
||||
#
|
||||
# To use:
|
||||
#
|
||||
# $ ./generate-spdx-syntax.py > ../syntax/spdx-comments.xml
|
||||
#
|
||||
|
||||
import json
|
||||
import pathlib
|
||||
import urllib.request
|
||||
|
||||
import click
|
||||
import jinja2
|
||||
|
||||
|
||||
def get_json(url):
|
||||
with urllib.request.urlopen(url=url) as body:
|
||||
return json.load(body)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument('template', type=click.File('r'), default='./spdx-comments.xml.tpl')
|
||||
def cli(template):
|
||||
|
||||
data = {
|
||||
'licenses': [
|
||||
*filter(
|
||||
lambda l: not l['licenseId'].endswith('+')
|
||||
, get_json(url='https://spdx.org/licenses/licenses.json')['licenses']
|
||||
)
|
||||
]
|
||||
, 'exceptions': [
|
||||
*filter(
|
||||
lambda l: not l['licenseExceptionId'].endswith('+')
|
||||
, get_json(url='https://spdx.org/licenses/exceptions.json')['exceptions']
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
env = jinja2.Environment(
|
||||
keep_trailing_newline=True
|
||||
)
|
||||
env.block_start_string = '<!--['
|
||||
env.block_end_string = ']-->'
|
||||
env.variable_start_string = '<!--{'
|
||||
env.variable_end_string = '}-->'
|
||||
env.comment_start_string = '<!--#'
|
||||
env.comment_end_string = '#-->'
|
||||
|
||||
tpl = env.from_string(template.read())
|
||||
result = tpl.render(data)
|
||||
print(result.strip(), end=None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
# TODO Handle execptions and show errors
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2012-2013 Alex Turbov
|
||||
#
|
||||
# Grab a documented (officially) class list from Qt project web site:
|
||||
# http://qt-project.org/doc/qt-${version}/classes.html
|
||||
#
|
||||
|
||||
version=$1
|
||||
shift
|
||||
|
||||
case "$version" in
|
||||
5*)
|
||||
url="http://qt-project.org/doc/qt-${version}/qtdoc/classes.html"
|
||||
;;
|
||||
4*)
|
||||
url="http://qt-project.org/doc/qt-${version}/classes.html"
|
||||
;;
|
||||
*)
|
||||
echo "*** Error: Only Qt4 and Qt5 supported!"
|
||||
esac
|
||||
|
||||
if [ -n "$version" ]; then
|
||||
tmp=`mktemp`
|
||||
wget -O $tmp "$url"
|
||||
cat $tmp | egrep '^<dd><a href=".*\.html">.*</a></dd>$' \
|
||||
| sed -e 's,<dd><a href=".*\.html">\(.*\)</a></dd>,<item> \1 </item>,' \
|
||||
| grep -v 'qoutputrange'
|
||||
rm $tmp
|
||||
else
|
||||
cat <<EOF
|
||||
Usage:
|
||||
$0 Qt-version
|
||||
|
||||
Note: Only major and minor version required
|
||||
|
||||
Example:
|
||||
$0 4.8
|
||||
EOF
|
||||
fi
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2011-2012 Alex Turbov
|
||||
#
|
||||
# Simplest (and stupid) way to get #defines from a header file(s)
|
||||
#
|
||||
# TODO Think about to use clang to get (an actual) list of free functions and/or types, classes, etc
|
||||
# Using python bindings it seems possible and not so hard to code...
|
||||
#
|
||||
|
||||
basepath=$1
|
||||
shift
|
||||
|
||||
if [ -n "$*" ]; then
|
||||
for f in $*; do
|
||||
egrep '^\s*#\s*define\s+(Q|QT|QT3)_' ${basepath}/$f
|
||||
done \
|
||||
| sed 's,^\s*#\s*define\s\+\(Q[A-Z0-9_]\+\).*,<item> \1 </item>,' \
|
||||
| sort \
|
||||
| uniq \
|
||||
| grep -v EXPORT \
|
||||
| grep -v QT_BEGIN_ \
|
||||
| grep -v QT_END_ \
|
||||
| grep -v QT_MANGLE_
|
||||
else
|
||||
cat <<EOF
|
||||
Usage:
|
||||
$0 basepath [qt-header-filenames]
|
||||
|
||||
Example:
|
||||
$0 /usr/include/qt4/Qt qglobal.h qconfig.h qfeatures.h
|
||||
EOF
|
||||
fi
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
tokens = []
|
||||
with open("makensiscmdhelp.output") as f: # output from `makensis /cmdhelp`
|
||||
for line in f:
|
||||
if line.startswith(" "):
|
||||
continue # line continuation
|
||||
|
||||
tokens.append(line.split()[0])
|
||||
|
||||
keywords = [x[1:] for x in tokens if x.startswith("!")]
|
||||
basefuncs = [x for x in tokens if not x.startswith("!")]
|
||||
|
||||
print("KEYWORDS")
|
||||
for keyword in keywords:
|
||||
print("<item> %s </item>" % keyword)
|
||||
print()
|
||||
|
||||
print("BASEFUNCS")
|
||||
for basefunc in basefuncs:
|
||||
print("<item> %s </item>" % basefunc)
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# SPDX-FileCopyrightText: 2016 Kevin Funk <kfunk@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
# This script will print XML-like code you can put into the qmake.xml
|
||||
# syntax definition file
|
||||
#
|
||||
# Prerequisite: You need to have a qtbase checkout somewhere
|
||||
#
|
||||
# Usage: qmake-gen.py /path/to/qtbase/
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
|
||||
qt5Source = sys.argv[1]
|
||||
|
||||
qmakeKeywords = subprocess.check_output("ag --nofilename 'QMAKE_[A-Z_0-9]+' {0}/mkspecs -o".format(qt5Source), shell=True).split(os.linesep)
|
||||
extraKeywords = subprocess.check_output("sed -nr 's/\\\section1 ([A-Z_0-9]{{2,100}}).*/\\1/p' {0}/qmake/doc/src/qmake-manual.qdoc".format(qt5Source), shell=True).split(os.linesep)
|
||||
keywords = []
|
||||
keywords = [x.strip() for x in qmakeKeywords]
|
||||
keywords += [x.strip() for x in extraKeywords]
|
||||
keywords = list(set(keywords)) # remove duplicates
|
||||
keywords.sort()
|
||||
|
||||
functions = subprocess.check_output("sed -nr 's/\{{ \\\"(.+)\\\", T_.+/\\1/p' {0}/qmake/library/qmakebuiltins.cpp".format(qt5Source), shell=True).split(os.linesep)
|
||||
functions.sort()
|
||||
|
||||
def printItems(container):
|
||||
for item in container:
|
||||
trimmedText = item.strip()
|
||||
if not trimmedText:
|
||||
continue
|
||||
|
||||
print("<item> %s </item>" % trimmedText)
|
||||
print()
|
||||
|
||||
print("KEYWORDS")
|
||||
printItems(keywords)
|
||||
|
||||
print("FUNCTIONS")
|
||||
printItems(functions)
|
||||
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE language>
|
||||
<!-- ***** THIS FILE WAS GENERATED BY A SCRIPT - DO NOT EDIT *****
|
||||
cd data/generators
|
||||
# increase version of spdx-comments.xml.tpl then
|
||||
./generate-spdx-syntax.py > ../syntax/spdx-comments.xml
|
||||
-->
|
||||
<language
|
||||
version="6"
|
||||
kateversion="3.1"
|
||||
name="SPDX-Comments"
|
||||
section="Other"
|
||||
extensions=""
|
||||
mimetype=""
|
||||
author="Alex Turbov (i.zaufi@gmail.com)"
|
||||
license="MIT"
|
||||
hidden="true"
|
||||
>
|
||||
<highlighting>
|
||||
<list name="tags">
|
||||
<item>SPDX-License-Identifier:</item>
|
||||
<item>SPDX-FileContributor:</item>
|
||||
<item>SPDX-FileCopyrightText:</item>
|
||||
<item>SPDX-LicenseInfoInFile:</item>
|
||||
</list>
|
||||
|
||||
<list name="operators">
|
||||
<item>AND</item>
|
||||
<item>OR</item>
|
||||
<item>WITH</item>
|
||||
</list>
|
||||
|
||||
<list name="licenses">
|
||||
<!--[- for license in licenses if not license.isDeprecatedLicenseId ]-->
|
||||
<item><!--{ license.licenseId }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<list name="deprecated-licenses">
|
||||
<!--[- for license in licenses if license.isDeprecatedLicenseId ]-->
|
||||
<item><!--{ license.licenseId }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<list name="exceptions">
|
||||
<!--[- for exception in exceptions if not exception.isDeprecatedLicenseId ]-->
|
||||
<item><!--{ exception.licenseExceptionId }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<list name="deprecated-exceptions">
|
||||
<!--[- for exception in exceptions if exception.isDeprecatedLicenseId ]-->
|
||||
<item><!--{ exception.licenseExceptionId }--></item>
|
||||
<!--[- endfor ]-->
|
||||
</list>
|
||||
|
||||
<contexts>
|
||||
|
||||
<context name="Normal" attribute="SPDX Tag" lineEndContext="#pop">
|
||||
<WordDetect String="SPDX-License-Identifier:" attribute="SPDX Tag" context="license-expression" />
|
||||
<keyword String="tags" attribute="SPDX Tag" />
|
||||
</context>
|
||||
|
||||
<context name="license-expression" attribute="SPDX Value" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
|
||||
<DetectSpaces/>
|
||||
<AnyChar String="()+" context="#stay" attribute="SPDX License Expression Operator" />
|
||||
<keyword String="licenses" context="#stay" attribute="SPDX License" />
|
||||
<keyword String="deprecated-licenses" context="#stay" attribute="SPDX Deprecated License" />
|
||||
<keyword String="exceptions" context="#stay" attribute="SPDX License Exception" />
|
||||
<keyword String="deprecated-exceptions" context="#stay" attribute="SPDX Deprecated License Exception" />
|
||||
<keyword String="operators" context="#stay" attribute="SPDX License Expression Operator" />
|
||||
<RegExpr attribute="SPDX License" context="#stay" String="\bLicenseRef-[^\s]+" />
|
||||
</context>
|
||||
|
||||
</contexts>
|
||||
|
||||
<itemDatas>
|
||||
<itemData name="SPDX Tag" defStyleNum="dsAnnotation" italic="true" spellChecking="false" />
|
||||
<itemData name="SPDX Value" defStyleNum="dsAnnotation" italic="true" spellChecking="false" />
|
||||
<itemData name="SPDX License" defStyleNum="dsAnnotation" italic="true" spellChecking="false" />
|
||||
<itemData name="SPDX License Exception" defStyleNum="dsAnnotation" italic="true" spellChecking="false" />
|
||||
<itemData name="SPDX Deprecated License" defStyleNum="dsAnnotation" italic="true" spellChecking="false" />
|
||||
<itemData name="SPDX Deprecated License Exception" defStyleNum="dsAnnotation" italic="true" spellChecking="false" />
|
||||
<itemData name="SPDX License Expression Operator" defStyleNum="dsOperator" italic="true" spellChecking="false" />
|
||||
</itemDatas>
|
||||
|
||||
</highlighting>
|
||||
|
||||
<general>
|
||||
<keywords casesensitive="1" weakDeliminator=":-." />
|
||||
</general>
|
||||
|
||||
</language>
|
||||
<!-- kate: indent-width 2; -->
|
||||
+498
@@ -0,0 +1,498 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-FileCopyrightText: 2023 Jonathan Poelen <jonathan.poelen@gmail.com>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
from typing import TextIO
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
exclude_line = {
|
||||
' - non-standard\n',
|
||||
' - experimental\n',
|
||||
' - deprecated\n',
|
||||
'page-type: css-combinator\n',
|
||||
'page-type: css-selector\n',
|
||||
'page-type: css-module\n',
|
||||
'page-type: landing-page\n',
|
||||
'page-type: guide\n',
|
||||
}
|
||||
|
||||
page_type_accepted = {
|
||||
'page-type: css-type\n',
|
||||
'page-type: css-function\n',
|
||||
'page-type: css-property\n',
|
||||
'page-type: css-keyword\n',
|
||||
'page-type: css-shorthand-property\n',
|
||||
'page-type: css-pseudo-element\n',
|
||||
'page-type: css-pseudo-class\n',
|
||||
'page-type: css-at-rule-descriptor\n',
|
||||
'page-type: css-at-rule\n',
|
||||
'page-type: css-media-feature\n',
|
||||
'page-type: svg-attribute\n',
|
||||
}
|
||||
|
||||
exclude_title = {
|
||||
'<alpha-value>',
|
||||
'<angle>',
|
||||
'<angle-percentage>',
|
||||
'<basic-shape>',
|
||||
'<calc-constant>',
|
||||
'<calc-sum>',
|
||||
'<color-interpolation-method>',
|
||||
'<color>',
|
||||
'<custom-ident>',
|
||||
'<dashed-ident>',
|
||||
'<display-listitem>',
|
||||
'<display-inside>',
|
||||
'<dimension>',
|
||||
'<easing-function>'
|
||||
'<filter-function>',
|
||||
'<flex>',
|
||||
'<frequency-percentage>',
|
||||
'<frequency>',
|
||||
'<gradient>',
|
||||
'<hex-color>',
|
||||
'<hue>',
|
||||
'<hue-interpolation-method>',
|
||||
'<ident>',
|
||||
'<image>',
|
||||
'<integer>',
|
||||
'<length>',
|
||||
'<length-percentage>',
|
||||
'<number>',
|
||||
'<percentage>',
|
||||
'<position>',
|
||||
'<ratio>',
|
||||
'<resolution>',
|
||||
'<string>',
|
||||
'<time-percentage>',
|
||||
'<time>',
|
||||
'<transform-function>',
|
||||
'"!important"',
|
||||
}
|
||||
|
||||
properties_ignore_value = (
|
||||
'counter-increment',
|
||||
'counter-reset',
|
||||
'counter-set',
|
||||
'text-rendering',
|
||||
'page',
|
||||
)
|
||||
|
||||
|
||||
units: list[str] = []
|
||||
colors: set[str] = set()
|
||||
system_colors: set[str] = set()
|
||||
deprecated_system_colors: set[str] = set()
|
||||
values: set[str] = set()
|
||||
properties: set[str] = set()
|
||||
svg_values: set[str] = set()
|
||||
svg_properties: set[str] = set()
|
||||
functions: set[str] = set()
|
||||
pseudo_classes: set[str] = set()
|
||||
pseudo_elements: set[str] = set()
|
||||
experimental_pseudo_classes: set[str] = set()
|
||||
experimental_pseudo_elements: set[str] = set()
|
||||
at_rules: set[str] = set()
|
||||
media_features: set[str] = set()
|
||||
media_feature_values: set[str] = set()
|
||||
|
||||
|
||||
_update_version_extractor = re.compile(r' version="(\d+)" ')
|
||||
|
||||
def update_version(s: str) -> str:
|
||||
return _update_version_extractor.sub(lambda m: f' version="{int(m[1])+1}" ', s, count=1)
|
||||
|
||||
|
||||
_md_value_extractor = re.compile(r'(?<=[^\w][ /])`([-\w][-\w\d]+(?:<[^>]+>[?+*])?)`')
|
||||
_html_value_extractor = re.compile(r'<code>([-\w][-\w\d]+)</code>')
|
||||
_is_md_value = re.compile(r'^\s*- `')
|
||||
_is_html_table_desc = re.compile(r'^\s+<td><code>')
|
||||
|
||||
def css_parse_values(f: TextIO, prop: str, values: set[str]) -> None:
|
||||
line:str = ''
|
||||
# Format:
|
||||
# ## Syntax or ### Syntax
|
||||
#
|
||||
# ```css
|
||||
# (optional)
|
||||
# ```
|
||||
# ## Values or ### Values or not...
|
||||
#
|
||||
# - `ident` or html table <td><code>....</code></td>
|
||||
#
|
||||
# ## SVG only ... (optional)
|
||||
# ## other title
|
||||
for line in f:
|
||||
if line.endswith('## Syntax\n') or line.endswith('## Values\n') or '## SVG only' in line:
|
||||
for line in f:
|
||||
if _is_md_value.match(line):
|
||||
if 'deprecated' not in line:
|
||||
values.update(_md_value_extractor.findall(line))
|
||||
elif line.startswith('#'):
|
||||
if not (line.endswith('## Values\n') or '## SVG only' in line
|
||||
or (prop == 'display'
|
||||
and (line.endswith('## Grouped values\n')
|
||||
or line.endswith('## Outside\n')
|
||||
or line.endswith('## Inside\n')
|
||||
or line.endswith('## List Item\n')
|
||||
or line.endswith('## Internal\n')
|
||||
or line.endswith('## Box\n')
|
||||
or line.endswith('## Precomposed\n')
|
||||
))
|
||||
):
|
||||
return
|
||||
elif line == '```css\n':
|
||||
for line in f:
|
||||
if line.startswith('```\n'):
|
||||
break
|
||||
elif _is_html_table_desc.match(line):
|
||||
values.update(_html_value_extractor.findall(line))
|
||||
|
||||
|
||||
def css_parse_named_colors(f: TextIO) -> set[str]:
|
||||
return set(re.findall('\n <td>(?:\n )?<code>([a-z]+)</code>', f.read()))
|
||||
|
||||
|
||||
def css_parse_units(f: TextIO) -> list[str]:
|
||||
return re.findall(r'`([^`]+)`', ''.join(re.findall(r'\n\| (`[^|]+)', f.read())))
|
||||
|
||||
|
||||
_svg_values_extractor = re.compile(r'<th scope="row">Value</th>\n\s*<td>(.*?)</td>', re.DOTALL)
|
||||
_svg_value_extractor = re.compile(r'<code>([-\w\d]+)</code>')
|
||||
|
||||
def css_parse_svg_attribute(f: TextIO, prop: str, properties: set[str], values: set[str]) -> None:
|
||||
contents = f.read()
|
||||
if 'can be used as a CSS property' in contents:
|
||||
properties.add(prop)
|
||||
m = _svg_values_extractor.search(contents)
|
||||
if m:
|
||||
values.update(_svg_value_extractor.findall(m[1]))
|
||||
|
||||
|
||||
_experimental_selector_extractor = re.compile(r'\n- {{CSSxRef([^}]+)}} {{Experimental_Inline}}')
|
||||
_selector_extractor = re.compile(r'":+([-\w\d]+)[()]*"')
|
||||
|
||||
def css_parse_pseudo_classes_or_elements(f: TextIO) -> tuple[
|
||||
set[str], # experimental
|
||||
list[str]
|
||||
]:
|
||||
s = f.read()
|
||||
experimental_str = ''.join(_experimental_selector_extractor.findall(s))
|
||||
return (set(_selector_extractor.findall(experimental_str)), _selector_extractor.findall(s))
|
||||
|
||||
|
||||
if len(sys.argv) < 5:
|
||||
print(f'''{Path(sys.argv[0]).name} content-main-directory syntax/css.xml sass-site-directory syntax/scss.xml
|
||||
|
||||
content-main-directory is https://github.com/mdn/content/ (https://github.com/mdn/content/archive/refs/heads/main.zip)
|
||||
sass-site-directory is https://github.com/sass/sass-site/tree/main (https://github.com/sass/sass-site/archive/refs/heads/main.zip)
|
||||
''', file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
css_dir = Path(sys.argv[1])
|
||||
css_filename = Path(sys.argv[2])
|
||||
scss_dir = Path(sys.argv[3])
|
||||
scss_filename = Path(sys.argv[4])
|
||||
|
||||
|
||||
tmp_pseudo_classes = (set(), ())
|
||||
tmp_pseudo_elements = (set(), ())
|
||||
|
||||
for pattern in (
|
||||
'files/en-us/web/svg/attribute/**/',
|
||||
'files/en-us/web/css/**/',
|
||||
):
|
||||
for md in css_dir.glob(pattern):
|
||||
with open(md/'index.md', encoding='utf8') as f:
|
||||
if f.readline() != '---\n':
|
||||
continue
|
||||
|
||||
title = f.readline()[7:-1]
|
||||
if title in exclude_title:
|
||||
continue
|
||||
|
||||
if title.startswith('"'):
|
||||
title = title[1:-1]
|
||||
|
||||
page_type = ''
|
||||
for line in f:
|
||||
if line in exclude_line:
|
||||
page_type = ''
|
||||
break
|
||||
|
||||
if line.startswith('page-type: '):
|
||||
if line not in page_type_accepted:
|
||||
raise Exception(f'Unknown {line[:-1]}')
|
||||
page_type = line[11:-1]
|
||||
|
||||
if line == '---\n':
|
||||
break
|
||||
|
||||
if page_type == 'css-property' or page_type == 'css-at-rule-descriptor':
|
||||
properties.add(title)
|
||||
if not title.endswith('-name') and title not in properties_ignore_value:
|
||||
css_parse_values(f, title, values)
|
||||
elif page_type == 'css-shorthand-property':
|
||||
properties.add(title)
|
||||
elif page_type == 'css-pseudo-class':
|
||||
pseudo_classes.add(title[1:].removesuffix('()'))
|
||||
elif page_type == 'css-pseudo-element':
|
||||
pseudo_elements.add(title[2:].removesuffix('()'))
|
||||
elif page_type == 'css-type':
|
||||
if title == '<named-color>':
|
||||
colors = css_parse_named_colors(f)
|
||||
if title == '<system-color>':
|
||||
css_parse_values(f, '', system_colors)
|
||||
deprecated_system_colors = set(re.findall('\n- `([^`]+)` {{deprecated_inline}}', f.read()))
|
||||
else:
|
||||
css_parse_values(f, '', values)
|
||||
elif page_type == 'css-function':
|
||||
functions.add(title[:-2])
|
||||
elif page_type == 'css-at-rule':
|
||||
at_rules.add(title)
|
||||
elif page_type == 'css-media-feature':
|
||||
media_features.add(title)
|
||||
css_parse_values(f, title, media_feature_values)
|
||||
elif page_type == 'css-keyword':
|
||||
values.add(title)
|
||||
elif title == 'CSS values and units':
|
||||
units = css_parse_units(f)
|
||||
elif title == 'Pseudo-classes':
|
||||
tmp_pseudo_classes = css_parse_pseudo_classes_or_elements(f)
|
||||
elif title == 'Pseudo-elements':
|
||||
tmp_pseudo_elements = css_parse_pseudo_classes_or_elements(f)
|
||||
elif page_type == 'svg-attribute':
|
||||
css_parse_svg_attribute(f, title, svg_properties, svg_values)
|
||||
elif title == 'CSS value functions':
|
||||
functions.update(re.findall(r'\n- {{CSSxRef\("[^"]+", "([-\w\d]+)\(\)"\)}}\n', f.read()))
|
||||
|
||||
|
||||
experimental_pseudo_classes = tmp_pseudo_classes[0]
|
||||
experimental_pseudo_classes -= pseudo_classes
|
||||
pseudo_classes.update(tmp_pseudo_classes[1])
|
||||
|
||||
experimental_pseudo_elements = tmp_pseudo_elements[0]
|
||||
experimental_pseudo_elements -= pseudo_elements
|
||||
pseudo_elements.update(tmp_pseudo_elements[1])
|
||||
|
||||
|
||||
global_values = {
|
||||
'auto',
|
||||
'inherit',
|
||||
'initial',
|
||||
'revert',
|
||||
'revert-layer',
|
||||
'unset',
|
||||
}
|
||||
values -= global_values
|
||||
svg_values -= global_values
|
||||
pseudo_classes -= experimental_pseudo_classes
|
||||
pseudo_elements -= experimental_pseudo_elements
|
||||
|
||||
# add values of functions
|
||||
values.update((
|
||||
# repeat()
|
||||
'auto-fill',
|
||||
'auto-fit',
|
||||
))
|
||||
|
||||
# move some keyword colors in values
|
||||
for special_color in ('transparent', 'currentcolor'):
|
||||
values.add(special_color)
|
||||
colors.discard(special_color)
|
||||
|
||||
# fix not specified value in mdn file
|
||||
if 'user-invalid' in experimental_pseudo_classes:
|
||||
pseudo_classes.discard('user-valid')
|
||||
experimental_pseudo_classes.add('user-valid')
|
||||
media_features.update((
|
||||
'min-width',
|
||||
'max-width',
|
||||
'min-height',
|
||||
'max-height',
|
||||
))
|
||||
|
||||
# fix errors in mdn file
|
||||
for e in ('has', 'host-context'):
|
||||
pseudo_classes.add(e)
|
||||
experimental_pseudo_classes.discard(e)
|
||||
|
||||
# @font-format functions
|
||||
functions.update((
|
||||
'format',
|
||||
'local',
|
||||
'tech',
|
||||
))
|
||||
|
||||
|
||||
# def show(name, values):
|
||||
# print(f'{name} ({len(values)}):')
|
||||
# print('\n'.join(sorted(values)), end='\n\n')
|
||||
#
|
||||
# show('properties', properties)
|
||||
# show('svg properties', svg_properties)
|
||||
# show('values', values)
|
||||
# show('svg values', svg_values)
|
||||
# show('global values', global_values)
|
||||
# show('functions', functions)
|
||||
# show('pseudo-classes', pseudo_classes)
|
||||
# show('pseudo-elements', pseudo_elements)
|
||||
# show('experimental pseudo-classes', experimental_pseudo_classes)
|
||||
# show('experimental pseudo-elements', experimental_pseudo_elements)
|
||||
# show('at-rules', at_rules)
|
||||
# show('media-features', media_features)
|
||||
# show('media-features values', media_feature_values)
|
||||
# show('colors', colors)
|
||||
# show('system colors', system_colors)
|
||||
# show('deprecated system colors', deprecated_system_colors)
|
||||
# show('units', units)
|
||||
# print('units reg:', '|'.join(units))
|
||||
|
||||
|
||||
#
|
||||
# Update CSS
|
||||
#
|
||||
|
||||
sep = '\n '
|
||||
css_replacements = {
|
||||
prop: f'</item>{sep}<item>'.join(sorted(seq))
|
||||
for prop, seq in (
|
||||
('properties', properties),
|
||||
('values', values),
|
||||
('value keywords', global_values),
|
||||
('functions', functions),
|
||||
('pseudo-classes', pseudo_classes),
|
||||
('pseudo-elements', pseudo_elements),
|
||||
('media features', media_features)
|
||||
)
|
||||
}
|
||||
for prop, seq in (('properties', svg_properties - properties), ('values', svg_values - values)):
|
||||
if seq:
|
||||
items = f'</item>{sep}<item>'.join(sorted(seq))
|
||||
css_replacements[prop] += f'</item>\n{sep}<!-- SVG only -->\n{sep}<item>{items}'
|
||||
|
||||
rep1 = f'</item>{sep}<item>'.join(sorted(colors))
|
||||
rep2 = f'</item>{sep}<item>'.join(sorted(system_colors))
|
||||
css_replacements['colors'] = f'{rep1}</item>{sep}{sep}<!-- System colors -->{sep}<item>{rep2}'
|
||||
|
||||
item_extractor = re.compile('<item>([^-<][^<]*)')
|
||||
|
||||
current_at_rules = set()
|
||||
|
||||
def _css_update_and_extract_items(m) -> str:
|
||||
seq = css_replacements.get(m[1])
|
||||
if seq:
|
||||
end = ' ' if m[3] == '</list>' else sep
|
||||
return f'<list name="{m[1]}">{sep}<item>{seq}</item>\n{end}{m[3]}'
|
||||
|
||||
current_at_rules.update(item_extractor.findall(m[2]))
|
||||
return m[0]
|
||||
|
||||
|
||||
css_content = css_filename.read_text()
|
||||
original_css_content = css_content
|
||||
|
||||
names = f"{'|'.join(css_replacements)}|at-rules(?: definitions)?"
|
||||
css_content = re.sub(rf'<list name="({names})">(.*?)(</list>|<!-- manual list -->)',
|
||||
_css_update_and_extract_items, css_content, flags=re.DOTALL)
|
||||
|
||||
_regexpr_unit_prefix = r'(<RegExpr attribute="Unit".*?String="\(%\|\()'
|
||||
regexpr_unit_extractor = re.compile(fr'{_regexpr_unit_prefix}([^)]+)')
|
||||
|
||||
css_content = regexpr_unit_extractor.sub('\\1' + "|".join(units), css_content, 1)
|
||||
|
||||
if original_css_content != css_content:
|
||||
css_content = update_version(css_content)
|
||||
css_filename.write_text(css_content)
|
||||
|
||||
|
||||
def show_at_rule_difference(language: str, old_at_rules: set[str], new_at_rules: set[str]) -> None:
|
||||
at_rule_added = new_at_rules - old_at_rules
|
||||
at_rule_removed = old_at_rules - new_at_rules
|
||||
nl = '\n '
|
||||
if at_rule_added or at_rule_removed:
|
||||
print(f"""\x1b[31m{language} At-rules requires a manual update
|
||||
New ({len(at_rule_added)}):\x1b[0m
|
||||
{nl.join(at_rule_added)}
|
||||
\x1b[31mRemoved ({len(at_rule_removed)}):\x1b[0m
|
||||
{nl.join(at_rule_removed)}""")
|
||||
|
||||
show_at_rule_difference('CSS', current_at_rules, at_rules)
|
||||
|
||||
#
|
||||
# Extract SCSS data
|
||||
#
|
||||
|
||||
scss_functions:list[str] = []
|
||||
scss_at_rules:set[str] = {'@content', '@return'}
|
||||
|
||||
_function_list_extractor = re.compile(r'{% function (.*?) %}')
|
||||
_function_extractor = re.compile(r"'([-._a-zA-Z0-9]+)\(")
|
||||
_at_rule_extractor = re.compile(r'@[-a-z0-9]+')
|
||||
|
||||
for md in sorted(scss_dir.glob('source/documentation/modules/**/*.md')):
|
||||
func_list = _function_list_extractor.findall(md.read_text())
|
||||
func_items = set(_function_extractor.findall(''.join(func_list)))
|
||||
scss_functions.append(f'\n{sep}<!-- {md.stem} -->')
|
||||
scss_functions.extend(f'{sep}<item>{func}</item>' for func in sorted(func_items - functions))
|
||||
|
||||
for md in scss_dir.glob('source/documentation/at-rules/**/*.md'):
|
||||
with open(md) as f:
|
||||
f.readline()
|
||||
scss_at_rules.update(_at_rule_extractor.findall(f.readline()))
|
||||
|
||||
subproperties = set(
|
||||
'-'.join(splitted[i:n])
|
||||
for prop in properties
|
||||
for splitted in (prop.rsplit('-', prop.count('-') - 1) # '-aaa-bbb' -> ['-aaa', 'bbb']
|
||||
if prop.startswith('-')
|
||||
else prop.split('-'), ) # 'aaa-bbb' -> ['aaa', 'bbb']
|
||||
for i in range(len(splitted))
|
||||
for n in range(i+1, len(splitted)+1)
|
||||
)
|
||||
|
||||
#
|
||||
# Update SCSS
|
||||
#
|
||||
|
||||
scss_current_at_rules = set()
|
||||
|
||||
def _scss_update_and_extract_items(m) -> str:
|
||||
name = m[1]
|
||||
|
||||
if name == 'functions':
|
||||
return f"""<list name="functions">
|
||||
<include>functions##CSS</include>
|
||||
|
||||
<!-- https://sass-lang.com/documentation/modules/ -->{f''.join(scss_functions)}
|
||||
</list>"""
|
||||
|
||||
if name == 'at-rules':
|
||||
scss_current_at_rules.update(_at_rule_extractor.findall(m[2]))
|
||||
return m[0]
|
||||
|
||||
# sub-properties
|
||||
items = f'</item>{sep}<item>'.join(sorted(subproperties - properties))
|
||||
return f'<list name="{name}">{sep}<item>{items}</item>\n </list>'
|
||||
|
||||
scss_content = scss_filename.read_text()
|
||||
original_scss_content = scss_content
|
||||
|
||||
scss_content = re.sub(r'<list name="(sub-properties|functions|at-rules)">(.*?)</list>',
|
||||
_scss_update_and_extract_items, scss_content, count=3, flags=re.DOTALL)
|
||||
|
||||
scss_content = re.sub(r'<!ENTITY pseudoclasses "[^"]*">',
|
||||
f'<!ENTITY pseudoclasses "{"|".join(sorted(pseudo_classes))}">',
|
||||
scss_content, count=1)
|
||||
|
||||
scss_content = regexpr_unit_extractor.sub('\\1' + "|".join(units), scss_content, 1)
|
||||
|
||||
if original_scss_content != scss_content:
|
||||
scss_content = update_version(scss_content)
|
||||
scss_filename.write_text(scss_content)
|
||||
|
||||
show_at_rule_difference('SCSS', scss_current_at_rules, scss_at_rules)
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-FileCopyrightText: 2023 Jonathan Poelen <jonathan.poelen@gmail.com>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from pathlib import Path
|
||||
from urllib import request
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
if len(sys.argv) < 1:
|
||||
print(f'{sys.argv[0]} syntax/less.xml', file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
#
|
||||
# Extract functions
|
||||
#
|
||||
|
||||
data = request.urlopen('https://lesscss.org/functions/').read().decode()
|
||||
|
||||
functions = re.findall(r'</a>([-_\w\d]+)</h3>', data, flags=re.DOTALL)
|
||||
functions.append('%')
|
||||
|
||||
#
|
||||
# Update syntax
|
||||
#
|
||||
|
||||
sep = '\n '
|
||||
new_list = f"""<list name="functions">
|
||||
<include>functions##CSS</include>
|
||||
|
||||
<!-- Less functions, @see http://lesscss.org/functions/ -->
|
||||
<item>{f'</item>{sep}<item>'.join(sorted(functions))}</item>
|
||||
</list>"""
|
||||
|
||||
less_filename = Path(sys.argv[1])
|
||||
less_content = less_filename.read_text()
|
||||
original_less_content = less_content
|
||||
less_content = re.sub(r'<list name="functions">.*?</list>',
|
||||
new_list, less_content, count=1, flags=re.DOTALL)
|
||||
|
||||
if original_less_content != less_content:
|
||||
less_content = re.sub(' version="(\d+)" ', lambda m: f' version="{int(m[1])+1}" ',
|
||||
less_content, count=1)
|
||||
less_filename.write_text(less_content)
|
||||
Reference in New Issue
Block a user