forked from qt-creator/qt-creator
Editor: update ksyntaxhighlighting engine to v5.90.0
Task-number: QTCREATORBUG-22558 Change-Id: I7314c146a6de359ea8d60750d8a2c8e972b33fc9 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -29,6 +29,7 @@ add_qtc_library(KSyntaxHighlighting SHARED
|
|||||||
src/lib/foldingregion.cpp src/lib/foldingregion.h
|
src/lib/foldingregion.cpp src/lib/foldingregion.h
|
||||||
src/lib/format.cpp src/lib/format.h src/lib/format_p.h
|
src/lib/format.cpp src/lib/format.h src/lib/format_p.h
|
||||||
src/lib/htmlhighlighter.cpp src/lib/htmlhighlighter.h
|
src/lib/htmlhighlighter.cpp src/lib/htmlhighlighter.h
|
||||||
|
src/lib/highlightingdata.cpp src/lib/highlightingdata_p.hpp
|
||||||
src/lib/keywordlist.cpp src/lib/keywordlist_p.h
|
src/lib/keywordlist.cpp src/lib/keywordlist_p.h
|
||||||
src/lib/matchresult_p.h
|
src/lib/matchresult_p.h
|
||||||
src/lib/repository.cpp src/lib/repository.h src/lib/repository_p.h
|
src/lib/repository.cpp src/lib/repository.h src/lib/repository_p.h
|
||||||
|
@@ -3,10 +3,10 @@
|
|||||||
#ifndef SyntaxHighlighting_VERSION_H
|
#ifndef SyntaxHighlighting_VERSION_H
|
||||||
#define SyntaxHighlighting_VERSION_H
|
#define SyntaxHighlighting_VERSION_H
|
||||||
|
|
||||||
#define SyntaxHighlighting_VERSION_STRING "5.87.0"
|
#define SyntaxHighlighting_VERSION_STRING "5.90.0"
|
||||||
#define SyntaxHighlighting_VERSION_MAJOR 5
|
#define SyntaxHighlighting_VERSION_MAJOR 5
|
||||||
#define SyntaxHighlighting_VERSION_MINOR 87
|
#define SyntaxHighlighting_VERSION_MINOR 90
|
||||||
#define SyntaxHighlighting_VERSION_PATCH 0
|
#define SyntaxHighlighting_VERSION_PATCH 0
|
||||||
#define SyntaxHighlighting_VERSION ((5<<16)|(87<<8)|(0))
|
#define SyntaxHighlighting_VERSION ((5<<16)|(90<<8)|(0))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -88,7 +88,7 @@
|
|||||||
#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1
|
#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1
|
||||||
|
|
||||||
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED
|
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED
|
||||||
# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700
|
# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55a00
|
||||||
#endif
|
#endif
|
||||||
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS
|
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS
|
||||||
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0
|
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
||||||
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
||||||
# else
|
# else
|
||||||
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700
|
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55a00
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1
|
#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1
|
||||||
|
|
||||||
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED
|
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED
|
||||||
# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700
|
# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55a00
|
||||||
#endif
|
#endif
|
||||||
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS
|
#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS
|
||||||
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0
|
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0
|
||||||
@@ -188,7 +188,7 @@
|
|||||||
# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
||||||
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT
|
||||||
# else
|
# else
|
||||||
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700
|
# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55a00
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -64,7 +64,7 @@ if (QRC_SYNTAX)
|
|||||||
|
|
||||||
# generate the qrc file manually, to make dependencies on generated files work...
|
# generate the qrc file manually, to make dependencies on generated files work...
|
||||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp"
|
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp"
|
||||||
COMMAND ${Qt5Core_RCC_EXECUTABLE} --name syntax_data -o "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" "${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc"
|
COMMAND Qt${QT_MAJOR_VERSION}::rcc --name syntax_data -o "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" "${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc"
|
||||||
DEPENDS ${defs} ${CMAKE_CURRENT_BINARY_DIR}/index.katesyntax
|
DEPENDS ${defs} ${CMAKE_CURRENT_BINARY_DIR}/index.katesyntax
|
||||||
)
|
)
|
||||||
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" PROPERTIES SKIP_AUTOMOC ON)
|
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" PROPERTIES SKIP_AUTOMOC ON)
|
||||||
@@ -79,5 +79,5 @@ endif()
|
|||||||
# this needs some more recent CMake than generally required
|
# this needs some more recent CMake than generally required
|
||||||
set_property(TARGET SyntaxHighlightingData PROPERTY POSITION_INDEPENDENT_CODE 1)
|
set_property(TARGET SyntaxHighlightingData PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.13.0")
|
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.13.0")
|
||||||
target_link_libraries(SyntaxHighlightingData PRIVATE Qt5::Core)
|
target_link_libraries(SyntaxHighlightingData PRIVATE Qt${QT_MAJOR_VERSION}::Core)
|
||||||
endif()
|
endif()
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE language SYSTEM "language.dtd"
|
<!DOCTYPE language SYSTEM "language.dtd"
|
||||||
[
|
[
|
||||||
<!ENTITY id_re "[_A-Za-z][\-_0-9A-Za-z]*">
|
<!-- 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.
|
This file is part of KDE's kate project.
|
||||||
@@ -38,7 +41,9 @@
|
|||||||
<item><!--{command.name}--></item>
|
<item><!--{command.name}--></item>
|
||||||
<!--[- endfor ]-->
|
<!--[- endfor ]-->
|
||||||
</list>
|
</list>
|
||||||
<!--[ for command in commands -]-->
|
|
||||||
|
<!--[- macro render_command_arg_lists(commands) ]-->
|
||||||
|
<!--[- for command in commands -]-->
|
||||||
<!--[- if command.named_args and command.named_args.kw ]-->
|
<!--[- if command.named_args and command.named_args.kw ]-->
|
||||||
<list name="<!--{command.name}-->_nargs">
|
<list name="<!--{command.name}-->_nargs">
|
||||||
<!--[- for arg in command.named_args.kw ]-->
|
<!--[- for arg in command.named_args.kw ]-->
|
||||||
@@ -54,6 +59,9 @@
|
|||||||
</list>
|
</list>
|
||||||
<!--[- endif ]-->
|
<!--[- endif ]-->
|
||||||
<!--[- endfor ]-->
|
<!--[- endfor ]-->
|
||||||
|
<!--[- endmacro ]-->
|
||||||
|
<!--{- render_command_arg_lists(commands) }-->
|
||||||
|
<!--{- render_command_arg_lists(standard_module_commands) }-->
|
||||||
|
|
||||||
<list name="variables">
|
<list name="variables">
|
||||||
<!--[- for var in variables.kw ]-->
|
<!--[- for var in variables.kw ]-->
|
||||||
@@ -87,6 +95,24 @@
|
|||||||
<!--[- endfor ]-->
|
<!--[- endfor ]-->
|
||||||
</list>
|
</list>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
<contexts>
|
<contexts>
|
||||||
|
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="Normal Text">
|
<context attribute="Normal Text" lineEndContext="#stay" name="Normal Text">
|
||||||
@@ -94,25 +120,68 @@
|
|||||||
<!--[ for command in commands -]-->
|
<!--[ for command in commands -]-->
|
||||||
<WordDetect String="<!--{command.name}-->" insensitive="true" attribute="Command" context="<!--{command.name}-->_ctx"<!--[ if command.start_region ]--> beginRegion="<!--{command.start_region}-->"<!--[ endif -]--> <!--[- if command.end_region ]--> endRegion="<!--{command.end_region}-->"<!--[ endif ]--> />
|
<WordDetect String="<!--{command.name}-->" insensitive="true" attribute="Command" context="<!--{command.name}-->_ctx"<!--[ if command.start_region ]--> beginRegion="<!--{command.start_region}-->"<!--[ endif -]--> <!--[- if command.end_region ]--> endRegion="<!--{command.end_region}-->"<!--[ endif ]--> />
|
||||||
<!--[ endfor -]-->
|
<!--[ 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" />
|
<DetectChar attribute="Comment" context="Match Comments and Docs" char="#" lookAhead="true" />
|
||||||
<DetectIdentifier attribute="User Function/Macro" context="User Function" />
|
<DetectIdentifier attribute="User Function/Macro" context="User Function" />
|
||||||
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&id_re;@" lookAhead="true" />
|
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&var_ref_re;@" lookAhead="true" />
|
||||||
<!-- Include keywords matching for language autocompleter work -->
|
<RegExpr attribute="Error" context="#stay" String=".*" />
|
||||||
<keyword attribute="Command" context="#stay" String="commands" />
|
|
||||||
</context>
|
</context>
|
||||||
|
<!--[- macro render_command_parsers(commands) ]-->
|
||||||
<!--[ for command in commands -]-->
|
<!--[ for command in commands -]-->
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx">
|
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx">
|
||||||
<DetectChar attribute="Normal Text" context="<!--{command.name}-->_ctx_op" char="(" />
|
<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>
|
</context>
|
||||||
|
<!--[- if command.first_arg_is_target ]-->
|
||||||
|
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op_tgt_first">
|
||||||
|
<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;" />
|
||||||
|
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||||
|
<IncludeRules context="User Function Args" />
|
||||||
|
<DetectSpaces />
|
||||||
|
<RegExpr attribute="Error" context="#stay" String=".*" />
|
||||||
|
</context>
|
||||||
|
<!--[- endif ]-->
|
||||||
|
<!--[- if command.first_args_are_targets ]-->
|
||||||
|
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op_tgts_first">
|
||||||
|
<!--[- 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" />
|
||||||
|
<RegExpr attribute="Targets" context="#stay" String="&tgt_name_re;" />
|
||||||
|
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||||
|
<IncludeRules context="User Function Args" />
|
||||||
|
<DetectSpaces />
|
||||||
|
<RegExpr attribute="Error" context="#stay" String=".*" />
|
||||||
|
</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">
|
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op">
|
||||||
<!--[- if command.nested_parentheses ]-->
|
<!--[- if command.nested_parentheses ]-->
|
||||||
<DetectChar attribute="Normal Text" context="<!--{command.name}-->_ctx_op_nested" char="(" />
|
<DetectChar attribute="Normal Text" context="<!--{command.name}-->_ctx_op_nested" char="(" />
|
||||||
<!--[- endif ]-->
|
<!--[- endif ]-->
|
||||||
<IncludeRules context="EndCmdPop2" />
|
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||||
<!--[- if command.named_args and command.named_args.kw ]-->
|
<!--[- 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 ]-->
|
||||||
|
<WordDetect String="<!--{command.has_target_names_after_kw}-->" attribute="Named Args" context="<!--{command.name}-->_tgts" />
|
||||||
|
<!--[- endif ]-->
|
||||||
<keyword attribute="Named Args" context="#stay" String="<!--{command.name}-->_nargs" />
|
<keyword attribute="Named Args" context="#stay" String="<!--{command.name}-->_nargs" />
|
||||||
<!--[- endif ]-->
|
<!--[- 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 ]-->
|
<!--[- if command.special_args and command.special_args.kw ]-->
|
||||||
<keyword attribute="Special Args" context="#stay" String="<!--{command.name}-->_sargs" />
|
<keyword attribute="Special Args" context="#stay" String="<!--{command.name}-->_sargs" />
|
||||||
<!--[- endif ]-->
|
<!--[- endif ]-->
|
||||||
@@ -132,9 +201,21 @@
|
|||||||
<!--[- endif ]-->
|
<!--[- endif ]-->
|
||||||
<!--[- endif ]-->
|
<!--[- endif ]-->
|
||||||
</context>
|
</context>
|
||||||
|
<!--[- endif ]-->
|
||||||
|
<!--[- if command.has_target_names_after_kw ]-->
|
||||||
|
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_tgts">
|
||||||
|
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||||
|
<keyword attribute="Named Args" context="#pop" String="<!--{command.name}-->_nargs" />
|
||||||
|
<RegExpr attribute="Aliased Targets" context="#stay" String="&tgt_name_re;::&tgt_name_re;(?:\:\:&tgt_name_re;)*" />
|
||||||
|
<RegExpr attribute="Targets" context="#stay" String="&tgt_name_re;" />
|
||||||
|
<IncludeRules context="User Function Args" />
|
||||||
|
<DetectSpaces />
|
||||||
|
<RegExpr attribute="Error" context="#stay" String=".*" />
|
||||||
|
</context>
|
||||||
|
<!--[- endif ]-->
|
||||||
<!--[- if command.nested_parentheses ]-->
|
<!--[- if command.nested_parentheses ]-->
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op_nested">
|
<context attribute="Normal Text" lineEndContext="#stay" name="<!--{command.name}-->_ctx_op_nested">
|
||||||
<IncludeRules context="EndCmdPop" />
|
<DetectChar attribute="Normal Text" context="#pop" char=")" />
|
||||||
<!--[- if command.named_args and command.named_args.kw ]-->
|
<!--[- if command.named_args and command.named_args.kw ]-->
|
||||||
<keyword attribute="Named Args" context="#stay" String="<!--{command.name}-->_nargs" />
|
<keyword attribute="Named Args" context="#stay" String="<!--{command.name}-->_nargs" />
|
||||||
<!--[- endif ]-->
|
<!--[- endif ]-->
|
||||||
@@ -153,33 +234,27 @@
|
|||||||
</context>
|
</context>
|
||||||
<!--[- endif ]-->
|
<!--[- endif ]-->
|
||||||
<!--[ endfor -]-->
|
<!--[ endfor -]-->
|
||||||
|
<!--[- endmacro -]-->
|
||||||
|
<!--{- render_command_parsers(commands) -}-->
|
||||||
|
<!--{- render_command_parsers(standard_module_commands) -}-->
|
||||||
<!--[ for kind in properties.kinds if properties[kind].re -]-->
|
<!--[ for kind in properties.kinds if properties[kind].re -]-->
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More <!--{ kind|replace('_', '-') }-->">
|
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More <!--{ kind|replace('_', '-') }-->">
|
||||||
<RegExpr attribute="Property" context="#stay" String="<!--{properties[kind].re}-->" />
|
<RegExpr attribute="Property" context="#stay" String="<!--{properties[kind].re}-->" />
|
||||||
</context><!--{ '\n' }-->
|
</context><!--{ '\n' }-->
|
||||||
<!--[ endfor -]-->
|
<!--[ endfor -]-->
|
||||||
|
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="EndCmdPop">
|
<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=")" />
|
<DetectChar attribute="Normal Text" context="#pop" char=")" />
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="EndCmdPop2">
|
|
||||||
<DetectChar attribute="Normal Text" context="#pop#pop" char=")" />
|
|
||||||
</context>
|
|
||||||
|
|
||||||
<context attribute="User Function/Macro" lineEndContext="#stay" name="User Function">
|
|
||||||
<DetectChar attribute="Normal Text" context="User Function Opened" char="(" />
|
|
||||||
<IncludeRules context="EndCmdPop2" />
|
|
||||||
</context>
|
|
||||||
|
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="User Function Opened">
|
<context attribute="Normal Text" lineEndContext="#stay" name="User Function Opened">
|
||||||
<IncludeRules context="EndCmdPop2" />
|
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||||
<IncludeRules context="User Function Args" />
|
<IncludeRules context="User Function Args" />
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Builtin Variables">
|
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Builtin Variables">
|
||||||
<RegExpr attribute="Internal Name" context="#stay" String="\b_&id_re;\b" />
|
<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="CMake Internal Variable" context="#stay" String="deprecated-or-internal-variables" insensitive="false" />
|
||||||
<keyword attribute="Builtin Variable" context="#stay" String="variables" insensitive="false" />
|
<keyword attribute="Builtin Variable" context="#stay" String="variables" insensitive="false" />
|
||||||
<IncludeRules context="Detect More Builtin Variables" />
|
<IncludeRules context="Detect More Builtin Variables" />
|
||||||
@@ -198,7 +273,7 @@
|
|||||||
<RegExpr attribute="Cache Variable Substitution" context="#stay" String="\$CACHE\{\s*[\w-]+\s*\}" />
|
<RegExpr attribute="Cache Variable Substitution" context="#stay" String="\$CACHE\{\s*[\w-]+\s*\}" />
|
||||||
<RegExpr attribute="Environment Variable Substitution" context="EnvVarSubst" String="\$?ENV\{" />
|
<RegExpr attribute="Environment Variable Substitution" context="EnvVarSubst" String="\$?ENV\{" />
|
||||||
<Detect2Chars attribute="Variable Substitution" context="VarSubst" char="$" char1="{" />
|
<Detect2Chars attribute="Variable Substitution" context="VarSubst" char="$" char1="{" />
|
||||||
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&id_re;@" lookAhead="true" />
|
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&var_ref_re;@" lookAhead="true" />
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context attribute="Environment Variable Substitution" lineEndContext="#pop" name="EnvVarSubst">
|
<context attribute="Environment Variable Substitution" lineEndContext="#pop" name="EnvVarSubst">
|
||||||
@@ -229,6 +304,15 @@
|
|||||||
<DetectChar attribute="@Variable Substitution" context="#pop#pop" char="@" />
|
<DetectChar attribute="@Variable Substitution" context="#pop#pop" char="@" />
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Normal Text" lineEndContext="#stay" name="Target Name">
|
||||||
|
<RegExpr attribute="Aliased Targets" context="#pop" String="&tgt_name_re;::&tgt_name_re;(?:\:\:&tgt_name_re;)*" />
|
||||||
|
<RegExpr attribute="Targets" context="#pop" String="&tgt_name_re;" />
|
||||||
|
<DetectChar attribute="Normal Text" context="#pop" char=")" lookAhead="true" />
|
||||||
|
<IncludeRules context="User Function Args" />
|
||||||
|
<DetectSpaces />
|
||||||
|
<RegExpr attribute="Error" context="#stay" String=".*" />
|
||||||
|
</context>
|
||||||
|
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="User Function Args">
|
<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="Normal Text" context="#stay" char="\" char1=")" />
|
<Detect2Chars attribute="Normal Text" context="#stay" char="\" char1=")" />
|
||||||
@@ -261,12 +345,12 @@
|
|||||||
<WordDetect attribute="False Special Arg" context="#stay" String="N" insensitive="true" />
|
<WordDetect attribute="False Special Arg" context="#stay" String="N" insensitive="true" />
|
||||||
<WordDetect attribute="False Special Arg" context="#stay" String="IGNORE" insensitive="true" />
|
<WordDetect attribute="False Special Arg" context="#stay" String="IGNORE" insensitive="true" />
|
||||||
<WordDetect attribute="False Special Arg" context="#stay" String="0" />
|
<WordDetect attribute="False Special Arg" context="#stay" String="0" />
|
||||||
<RegExpr attribute="False Special Arg" context="#stay" String="\b(?:&id_re;-)?NOTFOUND\b" />
|
<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]\b" />
|
<RegExpr attribute="Special Args" context="#stay" String="\bCMP[0-9][0-9][0-9][0-9]\b" />
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Aliased Targets">
|
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Aliased Targets">
|
||||||
<RegExpr attribute="Aliased Targets" context="#stay" String="\b&id_re;::&id_re;(?:\:\:&id_re;)*\b" />
|
<RegExpr attribute="Aliased Targets" context="#stay" String="&tgt_name_re;::&tgt_name_re;(?:\:\:&tgt_name_re;)*" />
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context attribute="Comment" lineEndContext="#pop" name="Match Comments">
|
<context attribute="Comment" lineEndContext="#pop" name="Match Comments">
|
||||||
@@ -330,9 +414,12 @@
|
|||||||
|
|
||||||
<itemDatas>
|
<itemDatas>
|
||||||
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false" />
|
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false" />
|
||||||
|
<itemData name="Comment" defStyleNum="dsComment" spellChecking="true" />
|
||||||
<itemData name="Command" defStyleNum="dsKeyword" spellChecking="false" />
|
<itemData name="Command" defStyleNum="dsKeyword" 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="User Function/Macro" defStyleNum="dsFunction" spellChecking="false" />
|
||||||
<itemData name="Property" defStyleNum="dsOthers" 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="Aliased Targets" defStyleNum="dsBaseN" spellChecking="false" />
|
||||||
<itemData name="Named Args" defStyleNum="dsOthers" spellChecking="false" />
|
<itemData name="Named Args" defStyleNum="dsOthers" spellChecking="false" />
|
||||||
<itemData name="Special Args" defStyleNum="dsOthers" spellChecking="false" />
|
<itemData name="Special Args" defStyleNum="dsOthers" spellChecking="false" />
|
||||||
@@ -351,8 +438,10 @@
|
|||||||
<itemData name="Standard Environment Variable" 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 Keyword" defStyleNum="dsKeyword" color="#b84040" selColor="#b84040" spellChecking="false" />
|
||||||
<itemData name="Generator Expression" defStyleNum="dsOthers" color="#b86050" selColor="#b86050" spellChecking="false" />
|
<itemData name="Generator Expression" defStyleNum="dsOthers" color="#b86050" selColor="#b86050" spellChecking="false" />
|
||||||
<itemData name="Comment" defStyleNum="dsComment" spellChecking="true" />
|
<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="Region Marker" defStyleNum="dsRegionMarker" spellChecking="false" />
|
||||||
|
<itemData name="Error" defStyleNum="dsError" spellChecking="false" />
|
||||||
</itemDatas>
|
</itemDatas>
|
||||||
|
|
||||||
</highlighting>
|
</highlighting>
|
||||||
@@ -360,7 +449,7 @@
|
|||||||
<general>
|
<general>
|
||||||
<comments>
|
<comments>
|
||||||
<comment name="singleLine" start="#" position="afterwhitespace" />
|
<comment name="singleLine" start="#" position="afterwhitespace" />
|
||||||
<comment name="multiLine" start="#[[" end="]]" region="BracketedComment"/>
|
<comment name="multiLine" start="#[[" end="]]" region="BracketedComment" />
|
||||||
</comments>
|
</comments>
|
||||||
<keywords casesensitive="1" weakDeliminator="." />
|
<keywords casesensitive="1" weakDeliminator="." />
|
||||||
</general>
|
</general>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,7 @@ def try_transform_placeholder_string_to_regex(name):
|
|||||||
if 'ARGV' in m:
|
if 'ARGV' in m:
|
||||||
return 'ARGV[0-9]+'
|
return 'ARGV[0-9]+'
|
||||||
|
|
||||||
return '&id_re;'.join(m) if 1 < len(m) else name
|
return '&var_ref_re;'.join(m) if 1 < len(m) else name
|
||||||
|
|
||||||
|
|
||||||
def try_placeholders_to_regex(names):
|
def try_placeholders_to_regex(names):
|
||||||
@@ -109,6 +109,26 @@ def transform_command(cmd):
|
|||||||
|
|
||||||
cmd['nested_parentheses'] = cmd['nested-parentheses?'] if 'nested-parentheses?' in cmd else False
|
cmd['nested_parentheses'] = cmd['nested-parentheses?'] if 'nested-parentheses?' in cmd else 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:
|
||||||
|
cmd['has_target_names_after_kw'] = cmd['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:
|
if 'nulary?' in cmd and cmd['nulary?'] and not can_be_nulary:
|
||||||
raise RuntimeError('Command `{}` w/ args declared nulary!?'.format(cmd['name']))
|
raise RuntimeError('Command `{}` w/ args declared nulary!?'.format(cmd['name']))
|
||||||
|
|
||||||
@@ -124,8 +144,7 @@ def transform_command(cmd):
|
|||||||
#BEGIN Jinja filters
|
#BEGIN Jinja filters
|
||||||
|
|
||||||
def cmd_is_nulary(cmd):
|
def cmd_is_nulary(cmd):
|
||||||
assert not ('named-args' in cmd or 'special-args' in cmd or 'property-args' in cmd)
|
return cmd.setdefault('nulary?', False)
|
||||||
return 'nulary?' in cmd and cmd['nulary?']
|
|
||||||
|
|
||||||
#END Jinja filters
|
#END Jinja filters
|
||||||
|
|
||||||
@@ -134,7 +153,7 @@ def cmd_is_nulary(cmd):
|
|||||||
@click.argument('input_yaml', type=click.File('r'))
|
@click.argument('input_yaml', type=click.File('r'))
|
||||||
@click.argument('template', type=click.File('r'), default='./cmake.xml.tpl')
|
@click.argument('template', type=click.File('r'), default='./cmake.xml.tpl')
|
||||||
def cli(input_yaml, template):
|
def cli(input_yaml, template):
|
||||||
data = yaml.load(input_yaml)
|
data = yaml.load(input_yaml, Loader=yaml.BaseLoader)
|
||||||
|
|
||||||
# Partition `variables` and `environment-variables` lists into "pure" (key)words and regexes to match
|
# Partition `variables` and `environment-variables` lists into "pure" (key)words and regexes to match
|
||||||
for var_key in _VAR_KIND_LIST:
|
for var_key in _VAR_KIND_LIST:
|
||||||
@@ -164,8 +183,16 @@ def cli(input_yaml, template):
|
|||||||
data['commands'] = list(
|
data['commands'] = list(
|
||||||
map(
|
map(
|
||||||
transform_command
|
transform_command
|
||||||
, data['scripting-commands'] + data['project-commands'] + data['ctest-commands'])
|
, 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
|
# Fix node names to be accessible from Jinja template
|
||||||
data['generator_expressions'] = data['generator-expressions']
|
data['generator_expressions'] = data['generator-expressions']
|
||||||
|
@@ -1,7 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE language SYSTEM "language.dtd">
|
<!DOCTYPE language SYSTEM "language.dtd">
|
||||||
|
<!-- ***** 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
|
<language
|
||||||
version="4"
|
version="6"
|
||||||
kateversion="3.1"
|
kateversion="3.1"
|
||||||
name="SPDX-Comments"
|
name="SPDX-Comments"
|
||||||
section="Other"
|
section="Other"
|
||||||
@@ -58,9 +63,7 @@
|
|||||||
|
|
||||||
<context name="license-expression" attribute="SPDX Value" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
|
<context name="license-expression" attribute="SPDX Value" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
|
||||||
<DetectSpaces/>
|
<DetectSpaces/>
|
||||||
<DetectChar char="(" context="#stay" attribute="SPDX License Expression Operator" />
|
<AnyChar String="()+" context="#stay" attribute="SPDX License Expression Operator" />
|
||||||
<DetectChar char=")" context="#stay" attribute="SPDX License Expression Operator" />
|
|
||||||
<DetectChar char="+" context="#stay" attribute="SPDX License Expression Operator" />
|
|
||||||
<keyword String="licenses" context="#stay" attribute="SPDX License" />
|
<keyword String="licenses" context="#stay" attribute="SPDX License" />
|
||||||
<keyword String="deprecated-licenses" context="#stay" attribute="SPDX Deprecated License" />
|
<keyword String="deprecated-licenses" context="#stay" attribute="SPDX Deprecated License" />
|
||||||
<keyword String="exceptions" context="#stay" attribute="SPDX License Exception" />
|
<keyword String="exceptions" context="#stay" attribute="SPDX License Exception" />
|
||||||
|
@@ -130,8 +130,8 @@
|
|||||||
extensions: A file glob or pattern to decide for which documents to use this syntax description
|
extensions: A file glob or pattern to decide for which documents to use this syntax description
|
||||||
style: The style that this highlighter provides. It is used through required-syntax-style by the indenters. [optional]
|
style: The style that this highlighter provides. It is used through required-syntax-style by the indenters. [optional]
|
||||||
mimetype: A list of mimetypes to decide for which documents to use this syntax description [optional]
|
mimetype: A list of mimetypes to decide for which documents to use this syntax description [optional]
|
||||||
version: Version number of this syntax description [optional]
|
version: Version number of this syntax description
|
||||||
kateversion: Kate version required for using this file [optional]
|
kateversion: Kate version required for using this file
|
||||||
casesensitive: Whether text is matched case sensitive. [boolean, optional, default=true] FIXME: This is not implemented yet
|
casesensitive: Whether text is matched case sensitive. [boolean, optional, default=true] FIXME: This is not implemented yet
|
||||||
priority: Priority of this language, if more than one are usable for the file [optional]
|
priority: Priority of this language, if more than one are usable for the file [optional]
|
||||||
author: Name of author of this hl file [optional]
|
author: Name of author of this hl file [optional]
|
||||||
|
@@ -39,7 +39,7 @@
|
|||||||
<!ENTITY arithmetic_as_subshell "\(((?:[^`'"()$]++|\$\{[^`'"(){}$]+\}|\$(?=[^{`'"()])|`[^`]*+`|\((?1)(?:[)]|(?=['"])))++)(?:[)](?=$|[^)])|["'])">
|
<!ENTITY arithmetic_as_subshell "\(((?:[^`'"()$]++|\$\{[^`'"(){}$]+\}|\$(?=[^{`'"()])|`[^`]*+`|\((?1)(?:[)]|(?=['"])))++)(?:[)](?=$|[^)])|["'])">
|
||||||
]>
|
]>
|
||||||
|
|
||||||
<language name="Bash" version="30" kateversion="5.79" section="Scripts" extensions="*.sh;*.bash;*.ebuild;*.eclass;*.nix;.bashrc;.bash_profile;.bash_login;.profile;PKGBUILD;APKBUILD" mimetype="application/x-shellscript" casesensitive="1" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL">
|
<language name="Bash" version="34" kateversion="5.79" section="Scripts" extensions="*.sh;*.bash;*.ebuild;*.eclass;*.exlib;*.exheres-0;.bashrc;.bash_profile;.bash_login;.profile;PKGBUILD;APKBUILD" mimetype="application/x-shellscript" casesensitive="1" author="Wilbert Berendsen (wilbert@kde.nl)" license="LGPL">
|
||||||
|
|
||||||
<!-- (c) 2004 by Wilbert Berendsen (wilbert@kde.nl)
|
<!-- (c) 2004 by Wilbert Berendsen (wilbert@kde.nl)
|
||||||
Changes by Matthew Woehlke (mw_triad@users.sourceforge.net)
|
Changes by Matthew Woehlke (mw_triad@users.sourceforge.net)
|
||||||
@@ -133,6 +133,9 @@
|
|||||||
<!-- /bin -->
|
<!-- /bin -->
|
||||||
<item>arch</item>
|
<item>arch</item>
|
||||||
<item>awk</item>
|
<item>awk</item>
|
||||||
|
<item>b2sum</item>
|
||||||
|
<item>base32</item>
|
||||||
|
<item>base64</item>
|
||||||
<item>bash</item>
|
<item>bash</item>
|
||||||
<item>bunzip2</item>
|
<item>bunzip2</item>
|
||||||
<item>bzcat</item>
|
<item>bzcat</item>
|
||||||
@@ -147,11 +150,15 @@
|
|||||||
<item>bzmore</item>
|
<item>bzmore</item>
|
||||||
<item>cat</item>
|
<item>cat</item>
|
||||||
<item>chattr</item>
|
<item>chattr</item>
|
||||||
|
<item>chcon</item>
|
||||||
<item>chgrp</item>
|
<item>chgrp</item>
|
||||||
<item>chmod</item>
|
<item>chmod</item>
|
||||||
<item>chown</item>
|
<item>chown</item>
|
||||||
<item>chvt</item>
|
<item>chvt</item>
|
||||||
|
<item>cksum</item>
|
||||||
<item>cp</item>
|
<item>cp</item>
|
||||||
|
<item>crontab</item>
|
||||||
|
<item>csplit</item>
|
||||||
<item>date</item>
|
<item>date</item>
|
||||||
<item>dd</item>
|
<item>dd</item>
|
||||||
<item>deallocvt</item>
|
<item>deallocvt</item>
|
||||||
@@ -165,9 +172,11 @@
|
|||||||
<item>dumpkeys</item>
|
<item>dumpkeys</item>
|
||||||
<item>ed</item>
|
<item>ed</item>
|
||||||
<item>egrep</item>
|
<item>egrep</item>
|
||||||
|
<item>expand</item>
|
||||||
<item>false</item>
|
<item>false</item>
|
||||||
<item>fgconsole</item>
|
<item>fgconsole</item>
|
||||||
<item>fgrep</item>
|
<item>fgrep</item>
|
||||||
|
<item>fold</item>
|
||||||
<item>fuser</item>
|
<item>fuser</item>
|
||||||
<item>gawk</item>
|
<item>gawk</item>
|
||||||
<item>getkeycodes</item>
|
<item>getkeycodes</item>
|
||||||
@@ -178,7 +187,9 @@
|
|||||||
<item>gunzip</item>
|
<item>gunzip</item>
|
||||||
<item>gzexe</item>
|
<item>gzexe</item>
|
||||||
<item>gzip</item>
|
<item>gzip</item>
|
||||||
|
<item>hostid</item>
|
||||||
<item>hostname</item>
|
<item>hostname</item>
|
||||||
|
<item>iconv</item>
|
||||||
<item>igawk</item>
|
<item>igawk</item>
|
||||||
<item>install</item>
|
<item>install</item>
|
||||||
<item>kbd_mode</item>
|
<item>kbd_mode</item>
|
||||||
@@ -206,6 +217,7 @@
|
|||||||
<item>lzmainfo</item>
|
<item>lzmainfo</item>
|
||||||
<item>lzmore</item>
|
<item>lzmore</item>
|
||||||
<item>mapscrn</item>
|
<item>mapscrn</item>
|
||||||
|
<item>md5sum</item>
|
||||||
<item>mesg</item>
|
<item>mesg</item>
|
||||||
<item>mkdir</item>
|
<item>mkdir</item>
|
||||||
<item>mkfifo</item>
|
<item>mkfifo</item>
|
||||||
@@ -217,20 +229,29 @@
|
|||||||
<item>nano</item>
|
<item>nano</item>
|
||||||
<item>netstat</item>
|
<item>netstat</item>
|
||||||
<item>nisdomainname</item>
|
<item>nisdomainname</item>
|
||||||
|
<item>nproc</item>
|
||||||
<item>nroff</item>
|
<item>nroff</item>
|
||||||
|
<item>numfmt</item>
|
||||||
<item>openvt</item>
|
<item>openvt</item>
|
||||||
|
<item>paste</item>
|
||||||
|
<item>pathchk</item>
|
||||||
<item>pgawk</item>
|
<item>pgawk</item>
|
||||||
<item>pidof</item>
|
<item>pidof</item>
|
||||||
<item>ping</item>
|
<item>ping</item>
|
||||||
|
<item>pinky</item>
|
||||||
|
<item>printenv</item>
|
||||||
<item>ps</item>
|
<item>ps</item>
|
||||||
<item>pstree</item>
|
<item>pstree</item>
|
||||||
|
<item>ptx</item>
|
||||||
<item>rbash</item>
|
<item>rbash</item>
|
||||||
<item>readlink</item>
|
<item>readlink</item>
|
||||||
|
<item>realpath</item>
|
||||||
<item>red</item>
|
<item>red</item>
|
||||||
<item>resizecons</item>
|
<item>resizecons</item>
|
||||||
<item>rm</item>
|
<item>rm</item>
|
||||||
<item>rmdir</item>
|
<item>rmdir</item>
|
||||||
<item>run-parts</item>
|
<item>run-parts</item>
|
||||||
|
<item>runcon</item>
|
||||||
<item>sash</item>
|
<item>sash</item>
|
||||||
<item>sed</item>
|
<item>sed</item>
|
||||||
<item>setfont</item>
|
<item>setfont</item>
|
||||||
@@ -239,22 +260,33 @@
|
|||||||
<item>setmetamode</item>
|
<item>setmetamode</item>
|
||||||
<item>setserial</item>
|
<item>setserial</item>
|
||||||
<item>sh</item>
|
<item>sh</item>
|
||||||
|
<item>sha1sum</item>
|
||||||
|
<item>sha224sum</item>
|
||||||
|
<item>sha256sum</item>
|
||||||
|
<item>sha384sum</item>
|
||||||
|
<item>sha512sum</item>
|
||||||
<item>showkey</item>
|
<item>showkey</item>
|
||||||
<item>shred</item>
|
<item>shred</item>
|
||||||
|
<item>shuf</item>
|
||||||
<item>sleep</item>
|
<item>sleep</item>
|
||||||
<item>ssed</item>
|
<item>ssed</item>
|
||||||
<item>stat</item>
|
<item>stat</item>
|
||||||
|
<item>stdbuf</item>
|
||||||
<item>stty</item>
|
<item>stty</item>
|
||||||
<item>su</item>
|
<item>su</item>
|
||||||
<item>sync</item>
|
<item>sync</item>
|
||||||
<item>tar</item>
|
<item>tar</item>
|
||||||
<item>tempfile</item>
|
<item>tempfile</item>
|
||||||
|
<item>timeout</item>
|
||||||
<item>touch</item>
|
<item>touch</item>
|
||||||
|
<item>tput</item>
|
||||||
<item>troff</item>
|
<item>troff</item>
|
||||||
<item>true</item>
|
<item>true</item>
|
||||||
<item>truncate</item>
|
<item>truncate</item>
|
||||||
|
<item>tty</item>
|
||||||
<item>umount</item>
|
<item>umount</item>
|
||||||
<item>uname</item>
|
<item>uname</item>
|
||||||
|
<item>unexpand</item>
|
||||||
<item>unicode_start</item>
|
<item>unicode_start</item>
|
||||||
<item>unicode_stop</item>
|
<item>unicode_stop</item>
|
||||||
<item>unlink</item>
|
<item>unlink</item>
|
||||||
@@ -263,6 +295,7 @@
|
|||||||
<item>utmpdump</item>
|
<item>utmpdump</item>
|
||||||
<item>uuidgen</item>
|
<item>uuidgen</item>
|
||||||
<item>vdir</item>
|
<item>vdir</item>
|
||||||
|
<item>vi</item>
|
||||||
<item>wall</item>
|
<item>wall</item>
|
||||||
<item>wc</item>
|
<item>wc</item>
|
||||||
<item>xz</item>
|
<item>xz</item>
|
||||||
@@ -336,6 +369,7 @@
|
|||||||
<item>gc</item>
|
<item>gc</item>
|
||||||
<item>gcc</item>
|
<item>gcc</item>
|
||||||
<item>clang</item>
|
<item>clang</item>
|
||||||
|
<item>clang++</item>
|
||||||
<item>valgrind</item>
|
<item>valgrind</item>
|
||||||
<item>xdg-open</item>
|
<item>xdg-open</item>
|
||||||
<item>cmake</item>
|
<item>cmake</item>
|
||||||
@@ -464,6 +498,19 @@
|
|||||||
|
|
||||||
<contexts>
|
<contexts>
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" name="Start" fallthroughContext="Command">
|
<context attribute="Normal Text" lineEndContext="#stay" name="Start" fallthroughContext="Command">
|
||||||
|
<IncludeRules context="BashOneLine"/>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<!-- used by other syntaxes -->
|
||||||
|
<context attribute="Normal Text" lineEndContext="#pop" name="FindOneLineBackq" fallthroughContext="#pop">
|
||||||
|
<DetectChar attribute="Backquote" context="OneLineBackq" char="`"/>
|
||||||
|
</context>
|
||||||
|
<context attribute="Normal Text" lineEndContext="#stay" name="OneLineBackq" fallthroughContext="Command">
|
||||||
|
<DetectChar attribute="Backquote" context="#pop" char="`"/>
|
||||||
|
<IncludeRules context="Start"/>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context attribute="Normal Text" lineEndContext="#pop" name="BashOneLine" fallthroughContext="Command">
|
||||||
<DetectSpaces attribute="Normal Text" context="#stay"/>
|
<DetectSpaces attribute="Normal Text" context="#stay"/>
|
||||||
<DetectChar attribute="Comment" context="Comment" char="#"/>
|
<DetectChar attribute="Comment" context="Comment" char="#"/>
|
||||||
<!-- start expression in double parentheses -->
|
<!-- start expression in double parentheses -->
|
||||||
@@ -1104,6 +1151,7 @@
|
|||||||
<!-- VarBracePrefix called as soon as ${! is encoutered -->
|
<!-- VarBracePrefix called as soon as ${! is encoutered -->
|
||||||
<context attribute="Variable" lineEndContext="#pop" name="VarBracePrefix">
|
<context attribute="Variable" lineEndContext="#pop" name="VarBracePrefix">
|
||||||
<DetectIdentifier attribute="Variable" context="#pop!VarBracePrefixSuffix"/>
|
<DetectIdentifier attribute="Variable" context="#pop!VarBracePrefixSuffix"/>
|
||||||
|
<Int attribute="Variable" context="#pop!VarBracePrefixSuffix"/>
|
||||||
</context>
|
</context>
|
||||||
<context attribute="Variable" lineEndContext="#pop" name="VarBracePrefixSuffix" fallthroughContext="#pop!VarError">
|
<context attribute="Variable" lineEndContext="#pop" name="VarBracePrefixSuffix" fallthroughContext="#pop!VarError">
|
||||||
<DetectChar attribute="Parameter Expansion" context="#pop" char="}"/>
|
<DetectChar attribute="Parameter Expansion" context="#pop" char="}"/>
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -90,7 +90,7 @@
|
|||||||
<!ENTITY checkbox "\[[ x]\](?=\s)">
|
<!ENTITY checkbox "\[[ x]\](?=\s)">
|
||||||
]>
|
]>
|
||||||
|
|
||||||
<language name="Markdown" version="19" kateversion="5.79" section="Markup" extensions="*.md;*.mmd;*.markdown" priority="15" author="Darrin Yeager, Claes Holmerson" license="GPL,BSD">
|
<language name="Markdown" version="21" kateversion="5.79" section="Markup" extensions="*.md;*.mmd;*.markdown" priority="15" author="Darrin Yeager, Claes Holmerson" license="GPL,BSD">
|
||||||
<highlighting>
|
<highlighting>
|
||||||
<contexts>
|
<contexts>
|
||||||
<!-- Start of the Markdown document: find metadata or code block -->
|
<!-- Start of the Markdown document: find metadata or code block -->
|
||||||
@@ -149,32 +149,42 @@
|
|||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context name="find-header" attribute="Normal Text" lineEndContext="#pop">
|
<context name="find-header" attribute="Normal Text" lineEndContext="#pop">
|
||||||
<!-- TODO: Replace "(?=.$)" in the regexes with just "$" when close-H#-region are removed -->
|
<RegExpr attribute="Header H1" context="#pop!close-H2-region" String="^(#\s.*[#]?)$" column="0" endRegion="H1" beginRegion="H1" lookAhead="true"/>
|
||||||
<RegExpr attribute="Header H1" context="#pop!close-H2-region" String="^#\s.*[#]?(?=.$)" column="0" endRegion="H1" beginRegion="H1"/>
|
<RegExpr attribute="Header H2" context="#pop!close-H3-region" String="^(##\s.*[#]?)$" column="0" endRegion="H2" beginRegion="H2" lookAhead="true"/>
|
||||||
<RegExpr attribute="Header H2" context="#pop!close-H3-region" String="^##\s.*[#]?(?=.$)" column="0" endRegion="H2" beginRegion="H2"/>
|
<RegExpr attribute="Header H3" context="#pop!close-H4-region" String="^(###\s.*[#]?)$" column="0" endRegion="H3" beginRegion="H3" lookAhead="true"/>
|
||||||
<RegExpr attribute="Header H3" context="#pop!close-H4-region" String="^###\s.*[#]?(?=.$)" column="0" endRegion="H3" beginRegion="H3"/>
|
<RegExpr attribute="Header H4" context="#pop!close-H5-region" String="^(####\s.*[#]?)$" column="0" endRegion="H4" beginRegion="H4" lookAhead="true"/>
|
||||||
<RegExpr attribute="Header H4" context="#pop!close-H5-region" String="^####\s.*[#]?(?=.$)" column="0" endRegion="H4" beginRegion="H4"/>
|
<RegExpr attribute="Header H5" context="#pop!close-H6-region" String="^(#####\s.*[#]?)$" column="0" endRegion="H5" beginRegion="H5" lookAhead="true"/>
|
||||||
<RegExpr attribute="Header H5" context="#pop!close-H6-region" String="^#####\s.*[#]?(?=.$)" column="0" endRegion="H5" beginRegion="H5"/>
|
<RegExpr attribute="Header H6" context="#pop!close-sentinel-region" String="^(######\s.*[#]?)$" column="0" endRegion="H6" beginRegion="H6" lookAhead="true"/>
|
||||||
<RegExpr attribute="Header H6" context="#pop" String="^######\s.*[#]?$" column="0" endRegion="H6" beginRegion="H6"/>
|
|
||||||
<DetectChar attribute="Normal Text" context="#pop" char="#"/>
|
<DetectChar attribute="Normal Text" context="#pop" char="#"/>
|
||||||
</context>
|
</context>
|
||||||
<!-- BUG: 441278 sub-headers should be closed when their parent header is closed (e.g. in h1 h2 h3 h1, h1-h3 should all be closed at the 2nd h1) -->
|
<!-- BUG: 441278 sub-headers should be closed when their parent header is closed (e.g. in h1 h2 h3 h1, h1-h3 should all be closed at the 2nd h1) -->
|
||||||
<!-- TODO: Port to a less hacky version (maybe a new attribute for declaring multiple endRegions) -->
|
<!-- TODO: Port to a less hacky version (maybe a new attribute for declaring multiple endRegions) -->
|
||||||
<context name="close-H2-region" attribute="Header H2" lineEndContext="#pop!close-H3-region" fallthroughContext="#pop!close-H3-region">
|
<context name="close-H2-region" attribute="Header H2" lineEndContext="#pop!close-H3-region" fallthroughContext="#pop!close-H3-region">
|
||||||
<RegExpr attribute="Header H2" context="#pop!close-H3-region" String="." lookAhead="true" endRegion="H2"/>
|
<RegExpr attribute="Header H2" context="#pop!close-H3-region" String="(%1)" dynamic="true" lookAhead="true" endRegion="H2"/>
|
||||||
</context>
|
</context>
|
||||||
<context name="close-H3-region" attribute="Header H3" lineEndContext="#pop!close-H4-region" fallthroughContext="#pop!close-H4-region">
|
<context name="close-H3-region" attribute="Header H3" lineEndContext="#pop!close-H4-region" fallthroughContext="#pop!close-H4-region">
|
||||||
<RegExpr attribute="Header H3" context="#pop!close-H4-region" String="." lookAhead="true" endRegion="H3"/>
|
<RegExpr attribute="Header H3" context="#pop!close-H4-region" String="(%1)" dynamic="true" lookAhead="true" endRegion="H3"/>
|
||||||
</context>
|
</context>
|
||||||
<context name="close-H4-region" attribute="Header H4" lineEndContext="#pop!close-H5-region" fallthroughContext="#pop!close-H5-region">
|
<context name="close-H4-region" attribute="Header H4" lineEndContext="#pop!close-H5-region" fallthroughContext="#pop!close-H5-region">
|
||||||
<RegExpr attribute="Header H4" context="#pop!close-H5-region" String="." lookAhead="true" endRegion="H4"/>
|
<RegExpr attribute="Header H4" context="#pop!close-H5-region" String="(%1)" dynamic="true" lookAhead="true" endRegion="H4"/>
|
||||||
</context>
|
</context>
|
||||||
<context name="close-H5-region" attribute="Header H5" lineEndContext="#pop!close-H6-region" fallthroughContext="#pop!close-H6-region">
|
<context name="close-H5-region" attribute="Header H5" lineEndContext="#pop!close-H6-region" fallthroughContext="#pop!close-H6-region">
|
||||||
<RegExpr attribute="Header H5" context="#pop!close-H6-region" String="." lookAhead="true" endRegion="H5"/>
|
<RegExpr attribute="Header H5" context="#pop!close-H6-region" String="(%1)" dynamic="true" lookAhead="true" endRegion="H5"/>
|
||||||
</context>
|
</context>
|
||||||
<context name="close-H6-region" attribute="Header H6" lineEndContext="#pop" fallthroughContext="#pop">
|
<context name="close-H6-region" attribute="Header H6" lineEndContext="#pop" fallthroughContext="#pop">
|
||||||
<RegExpr attribute="Header H6" context="#pop" String="." endRegion="H6"/>
|
<RegExpr attribute="Header H6" context="#pop!close-sentinel-region" String="(%1)" dynamic="true" lookAhead="true" endRegion="H6"/>
|
||||||
</context>
|
</context>
|
||||||
|
<!-- This sentinel does not close any actual region, it's just here so that the proper attribute/highlighting is applied and -->
|
||||||
|
<!--to ensure that H6 headers won't be set as the "primary" region that was closed just because it was closed last -->
|
||||||
|
<context name="close-sentinel-region" attribute="Normal Text" lineEndContext="#pop" fallthroughContext="#pop">
|
||||||
|
<RegExpr attribute="Header H1" context="#pop" String="^(?=#\s)%1$" column="0" dynamic="true"/>
|
||||||
|
<RegExpr attribute="Header H2" context="#pop" String="^(?=##\s)%1$" column="0" dynamic="true"/>
|
||||||
|
<RegExpr attribute="Header H3" context="#pop" String="^(?=###\s)%1$" column="0" dynamic="true"/>
|
||||||
|
<RegExpr attribute="Header H4" context="#pop" String="^(?=####\s)%1$" column="0" dynamic="true"/>
|
||||||
|
<RegExpr attribute="Header H5" context="#pop" String="^(?=#####\s)%1$" column="0" dynamic="true"/>
|
||||||
|
<RegExpr attribute="Header H6" context="#pop" String="^(?=######\s)%1$" column="0" dynamic="true"/>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
|
||||||
<context name="find-strong-normal" attribute="Normal Text" lineEndContext="#pop">
|
<context name="find-strong-normal" attribute="Normal Text" lineEndContext="#pop">
|
||||||
<RegExpr attribute="Strong-Emphasis Text" context="#pop" minimal="true" String="&strongemphasisregex_ast_und;|&strongemphasisregex_ast_und2;"/>
|
<RegExpr attribute="Strong-Emphasis Text" context="#pop" minimal="true" String="&strongemphasisregex_ast_und;|&strongemphasisregex_ast_und2;"/>
|
||||||
@@ -320,6 +330,7 @@
|
|||||||
<RegExpr attribute="Fenced Code" context="#pop!javascript-code" String="&fcode;\s*(?:javascript|m?js|es6|kwinscript|julius)&end;" insensitive="true"/>
|
<RegExpr attribute="Fenced Code" context="#pop!javascript-code" String="&fcode;\s*(?:javascript|m?js|es6|kwinscript|julius)&end;" insensitive="true"/>
|
||||||
<RegExpr attribute="Fenced Code" context="#pop!jsx-code" String="&fcode;\s*(?:jsx|tsx|(?:java|type)script\-react)&end;" insensitive="true"/> <!-- Included in the HTML definition. Also apply for TSX. -->
|
<RegExpr attribute="Fenced Code" context="#pop!jsx-code" String="&fcode;\s*(?:jsx|tsx|(?:java|type)script\-react)&end;" insensitive="true"/> <!-- Included in the HTML definition. Also apply for TSX. -->
|
||||||
<RegExpr attribute="Fenced Code" context="#pop!json-code" String="&fcode;\s*(?:json5?|gltf)&end;" insensitive="true"/>
|
<RegExpr attribute="Fenced Code" context="#pop!json-code" String="&fcode;\s*(?:json5?|gltf)&end;" insensitive="true"/>
|
||||||
|
<RegExpr attribute="Fenced Code" context="#pop!yaml-code" String="&fcode;\s*(?:ya?ml)&end;" insensitive="true"/>
|
||||||
<RegExpr attribute="Fenced Code" context="#pop!matlab-code" String="&fcode;\s*matlab&end;" insensitive="true"/>
|
<RegExpr attribute="Fenced Code" context="#pop!matlab-code" String="&fcode;\s*matlab&end;" insensitive="true"/>
|
||||||
<RegExpr attribute="Fenced Code" context="#pop!markdown-code" String="&fcode;\s*(?:markdown|m?md)&end;" insensitive="true"/>
|
<RegExpr attribute="Fenced Code" context="#pop!markdown-code" String="&fcode;\s*(?:markdown|m?md)&end;" insensitive="true"/>
|
||||||
<RegExpr attribute="Fenced Code" context="#pop!mustache-code" String="&fcode;\s*(?:handlebars|hbs|mustache|mst|ractive|hogan|hulk)&end;" insensitive="true"/> <!-- Included in the HTML definition -->
|
<RegExpr attribute="Fenced Code" context="#pop!mustache-code" String="&fcode;\s*(?:handlebars|hbs|mustache|mst|ractive|hogan|hulk)&end;" insensitive="true"/> <!-- Included in the HTML definition -->
|
||||||
@@ -404,6 +415,10 @@
|
|||||||
<IncludeRules context="code"/>
|
<IncludeRules context="code"/>
|
||||||
<IncludeRules context="##JSON" includeAttrib="true"/>
|
<IncludeRules context="##JSON" includeAttrib="true"/>
|
||||||
</context>
|
</context>
|
||||||
|
<context attribute="Normal Text" lineEndContext="#stay" name="yaml-code">
|
||||||
|
<IncludeRules context="code"/>
|
||||||
|
<IncludeRules context="##YAML" includeAttrib="true"/>
|
||||||
|
</context>
|
||||||
<context attribute="Normal Text" lineEndContext="#stay" lineEmptyContext="find-code-block" name="markdown-code">
|
<context attribute="Normal Text" lineEndContext="#stay" lineEmptyContext="find-code-block" name="markdown-code">
|
||||||
<IncludeRules context="code"/>
|
<IncludeRules context="code"/>
|
||||||
<IncludeRules context="Normal Text"/>
|
<IncludeRules context="Normal Text"/>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -162,9 +162,9 @@
|
|||||||
"MarkError": "#cc0000",
|
"MarkError": "#cc0000",
|
||||||
"MarkExecution": "#888a85",
|
"MarkExecution": "#888a85",
|
||||||
"MarkWarning": "#ad7fa8",
|
"MarkWarning": "#ad7fa8",
|
||||||
"ModifiedLines": "#451e1a",
|
"ModifiedLines": "#cc0000",
|
||||||
"ReplaceHighlight": "#356703",
|
"ReplaceHighlight": "#356703",
|
||||||
"SavedLines": "#23321a",
|
"SavedLines": "#4e9a06",
|
||||||
"SearchHighlight": "#4e9a06",
|
"SearchHighlight": "#4e9a06",
|
||||||
"Separator": "#787775",
|
"Separator": "#787775",
|
||||||
"SpellChecking": "#e85848",
|
"SpellChecking": "#e85848",
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
add_subdirectory(indexer)
|
add_subdirectory(indexer)
|
||||||
if(TARGET Qt5::Gui)
|
if(TARGET Qt${QT_MAJOR_VERSION}::Gui)
|
||||||
add_subdirectory(lib)
|
add_subdirectory(lib)
|
||||||
add_subdirectory(cli)
|
add_subdirectory(cli)
|
||||||
endif()
|
endif()
|
||||||
|
if(TARGET Qt${QT_MAJOR_VERSION}::Quick)
|
||||||
|
add_subdirectory(quick)
|
||||||
|
endif()
|
||||||
|
|
||||||
ecm_qt_install_logging_categories(
|
ecm_qt_install_logging_categories(
|
||||||
EXPORT KSYNTAXHIGHLIGHTING
|
EXPORT KSYNTAXHIGHLIGHTING
|
||||||
|
@@ -20,6 +20,7 @@ elseif(CMAKE_CROSSCOMPILING)
|
|||||||
-DECM_DIR=${ECM_DIR} -DCMAKE_PREFIX_PATH=${NATIVE_PREFIX}
|
-DECM_DIR=${ECM_DIR} -DCMAKE_PREFIX_PATH=${NATIVE_PREFIX}
|
||||||
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
|
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/native_katehighlightingindexer-prefix/src/native_katehighlightingindexer-build/bin/katehighlightingindexer
|
||||||
)
|
)
|
||||||
add_executable(katehighlightingindexer IMPORTED GLOBAL)
|
add_executable(katehighlightingindexer IMPORTED GLOBAL)
|
||||||
add_dependencies(katehighlightingindexer native_katehighlightingindexer)
|
add_dependencies(katehighlightingindexer native_katehighlightingindexer)
|
||||||
@@ -32,6 +33,6 @@ else()
|
|||||||
if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS)
|
if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS)
|
||||||
target_link_libraries(katehighlightingindexer Qt5::XmlPatterns)
|
target_link_libraries(katehighlightingindexer Qt5::XmlPatterns)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(katehighlightingindexer Qt5::Core)
|
target_link_libraries(katehighlightingindexer Qt${QT_MAJOR_VERSION}::Core)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@@ -350,7 +350,7 @@ private:
|
|||||||
|
|
||||||
friend uint qHash(const Item &item, uint seed = 0)
|
friend uint qHash(const Item &item, uint seed = 0)
|
||||||
{
|
{
|
||||||
return uint(qHash(item.content, seed));
|
return qHash(item.content, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(const Item &item0, const Item &item1)
|
friend bool operator==(const Item &item0, const Item &item1)
|
||||||
@@ -513,7 +513,7 @@ private:
|
|||||||
static const QRegularExpression isDot(QStringLiteral(R"(^\(?\.(?:[*+][*+?]?|[*+]|\{1\})?\$?$)"));
|
static const QRegularExpression isDot(QStringLiteral(R"(^\(?\.(?:[*+][*+?]?|[*+]|\{1\})?\$?$)"));
|
||||||
// remove "(?:" and ")"
|
// remove "(?:" and ")"
|
||||||
static const QRegularExpression removeParentheses(QStringLiteral(R"(\((?:\?:)?|\))"));
|
static const QRegularExpression removeParentheses(QStringLiteral(R"(\((?:\?:)?|\))"));
|
||||||
// remove parentheses on a double from the string
|
// remove parentheses on a copy of string
|
||||||
auto reg = QString(string).replace(removeParentheses, QString());
|
auto reg = QString(string).replace(removeParentheses, QString());
|
||||||
isDotRegex = reg.contains(isDot);
|
isDotRegex = reg.contains(isDot);
|
||||||
}
|
}
|
||||||
@@ -719,7 +719,7 @@ private:
|
|||||||
|
|
||||||
friend uint qHash(const Style &style, uint seed = 0)
|
friend uint qHash(const Style &style, uint seed = 0)
|
||||||
{
|
{
|
||||||
return uint(qHash(style.name, seed));
|
return qHash(style.name, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(const Style &style0, const Style &style1)
|
friend bool operator==(const Style &style0, const Style &style1)
|
||||||
@@ -995,7 +995,6 @@ private:
|
|||||||
}
|
}
|
||||||
success = checkLookAhead(rule) && success;
|
success = checkLookAhead(rule) && success;
|
||||||
success = checkStringDetect(rule) && success;
|
success = checkStringDetect(rule) && success;
|
||||||
success = checkAnyChar(rule) && success;
|
|
||||||
success = checkKeyword(definition, rule, referencedKeywords) && success;
|
success = checkKeyword(definition, rule, referencedKeywords) && success;
|
||||||
success = checkRegExpr(filename, rule, context) && success;
|
success = checkRegExpr(filename, rule, context) && success;
|
||||||
success = checkDelimiters(definition, rule) && success;
|
success = checkDelimiters(definition, rule) && success;
|
||||||
@@ -1053,12 +1052,9 @@ private:
|
|||||||
"\\.\\*[?*]?" REG_CHAR "|"
|
"\\.\\*[?*]?" REG_CHAR "|"
|
||||||
"\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1"
|
"\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1"
|
||||||
")$"));
|
")$"));
|
||||||
if (( rule.lookAhead == XmlBool::True
|
if ((rule.lookAhead == XmlBool::True || rule.minimal == XmlBool::True || rule.string.contains(QStringLiteral(".*?"))
|
||||||
|| rule.minimal == XmlBool::True
|
|| rule.string.contains(QStringLiteral("[^")))
|
||||||
|| rule.string.contains(QStringLiteral(".*?"))
|
&& reg.contains(isRange)) {
|
||||||
|| rule.string.contains(QStringLiteral("[^"))
|
|
||||||
) && reg.contains(isRange)
|
|
||||||
) {
|
|
||||||
qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string;
|
qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1079,13 +1075,10 @@ private:
|
|||||||
#undef REG_ESCAPE_CHAR
|
#undef REG_ESCAPE_CHAR
|
||||||
|
|
||||||
// use minimal or lazy operator
|
// use minimal or lazy operator
|
||||||
static const QRegularExpression isMinimal(QStringLiteral(
|
static const QRegularExpression isMinimal(QStringLiteral(R"([.][*+][^][?+*()|$]*$)"));
|
||||||
R"([.][*+][^][?+*()|$]*$)"));
|
if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(isMinimal)) {
|
||||||
if (rule.lookAhead == XmlBool::True
|
qWarning() << filename << "line" << rule.line
|
||||||
&& rule.minimal != XmlBool::True
|
<< "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string;
|
||||||
&& reg.contains(isMinimal)
|
|
||||||
) {
|
|
||||||
qWarning() << filename << "line" << rule.line << "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1179,19 +1172,18 @@ private:
|
|||||||
if (*first == QLatin1Char('^')) {
|
if (*first == QLatin1Char('^')) {
|
||||||
hasStartOfLine = true;
|
hasStartOfLine = true;
|
||||||
break;
|
break;
|
||||||
}
|
} else if (*first == QLatin1Char('(')) {
|
||||||
else if (*first == QLatin1Char('(')) {
|
|
||||||
if (last - first >= 3 && first[1] == QLatin1Char('?') && first[2] == QLatin1Char(':')) {
|
if (last - first >= 3 && first[1] == QLatin1Char('?') && first[2] == QLatin1Char(':')) {
|
||||||
first += 2;
|
first += 2;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasStartOfLine) {
|
if (!hasStartOfLine) {
|
||||||
qWarning() << rule.filename << "line" << rule.line << "start of line missing in the pattern with column=\"0\" (i.e. abc -> ^abc):" << rule.string;
|
qWarning() << rule.filename << "line" << rule.line
|
||||||
|
<< "start of line missing in the pattern with column=\"0\" (i.e. abc -> ^abc):" << rule.string;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1314,14 +1306,12 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unnecessary quantifier
|
// unnecessary quantifier
|
||||||
static const QRegularExpression unnecessaryQuantifier1(QStringLiteral(
|
static const QRegularExpression unnecessaryQuantifier1(QStringLiteral(R"([*+?]([.][*+?]{0,2})?$)"));
|
||||||
R"([*+?]([.][*+?]{0,2})?$)"));
|
static const QRegularExpression unnecessaryQuantifier2(QStringLiteral(R"([*+?]([.][*+?]{0,2})?[)]*$)"));
|
||||||
static const QRegularExpression unnecessaryQuantifier2(QStringLiteral(
|
|
||||||
R"([*+?]([.][*+?]{0,2})?[)]*$)"));
|
|
||||||
auto &unnecessaryQuantifier = useCapture ? unnecessaryQuantifier1 : unnecessaryQuantifier2;
|
auto &unnecessaryQuantifier = useCapture ? unnecessaryQuantifier1 : unnecessaryQuantifier2;
|
||||||
if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(unnecessaryQuantifier)) {
|
if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(unnecessaryQuantifier)) {
|
||||||
qWarning() << filename << "line" << rule.line << "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):"
|
qWarning() << filename << "line" << rule.line
|
||||||
<< rule.string;
|
<< "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):" << rule.string;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1484,32 +1474,11 @@ private:
|
|||||||
qWarning() << rule.filename << "line" << rule.line << "broken regex:" << rule.string << "problem: dynamic=true but no %\\d+ placeholder";
|
qWarning() << rule.filename << "line" << rule.line << "broken regex:" << rule.string << "problem: dynamic=true but no %\\d+ placeholder";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (rule.string.size() <= 1) {
|
|
||||||
const auto replacement = rule.insensitive == XmlBool::True ? QStringLiteral("AnyChar") : QStringLiteral("DetectChar");
|
|
||||||
qWarning() << rule.filename << "line" << rule.line << "StringDetect should be replaced by" << replacement;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule.string.size() <= 2 && rule.insensitive != XmlBool::True) {
|
|
||||||
qWarning() << rule.filename << "line" << rule.line << "StringDetect should be replaced by Detect2Chars";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Check that AnyChar contains more that 1 character
|
|
||||||
bool checkAnyChar(const Context::Rule &rule) const
|
|
||||||
{
|
|
||||||
if (rule.type == Context::Rule::Type::AnyChar && rule.string.size() <= 1) {
|
|
||||||
qWarning() << rule.filename << "line" << rule.line << "AnyChar should be replaced by DetectChar";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Check \<include> and delimiter in a keyword list
|
//! Check \<include> and delimiter in a keyword list
|
||||||
bool checkKeywordsList(const Definition &definition, QSet<const Keywords *> &referencedKeywords) const
|
bool checkKeywordsList(const Definition &definition, QSet<const Keywords *> &referencedKeywords) const
|
||||||
{
|
{
|
||||||
@@ -1895,7 +1864,7 @@ private:
|
|||||||
Rule4 detectIdentifierRule{};
|
Rule4 detectIdentifierRule{};
|
||||||
|
|
||||||
// Contains includedRules and included includedRules
|
// Contains includedRules and included includedRules
|
||||||
QMap<Context const*, RuleAndInclude> includeContexts;
|
QMap<Context const *, RuleAndInclude> includeContexts;
|
||||||
|
|
||||||
DotRegex dotRegex;
|
DotRegex dotRegex;
|
||||||
|
|
||||||
@@ -2232,8 +2201,7 @@ private:
|
|||||||
|
|
||||||
if (auto &ruleAndInclude = includeContexts[rule.context.context]) {
|
if (auto &ruleAndInclude = includeContexts[rule.context.context]) {
|
||||||
updateUnreachable1(ruleAndInclude);
|
updateUnreachable1(ruleAndInclude);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ruleAndInclude.rule = &rule;
|
ruleAndInclude.rule = &rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2378,55 +2346,52 @@ private:
|
|||||||
const auto end = context.rules.end() - 1;
|
const auto end = context.rules.end() - 1;
|
||||||
|
|
||||||
for (; it < end; ++it) {
|
for (; it < end; ++it) {
|
||||||
auto& rule1 = *it;
|
auto &rule1 = *it;
|
||||||
auto& rule2 = it[1];
|
auto &rule2 = it[1];
|
||||||
|
|
||||||
auto isCommonCompatible = [&]{
|
auto isCommonCompatible = [&] {
|
||||||
return rule1.attribute == rule2.attribute
|
return rule1.attribute == rule2.attribute && rule1.beginRegion == rule2.beginRegion && rule1.endRegion == rule2.endRegion
|
||||||
&& rule1.beginRegion == rule2.beginRegion
|
&& rule1.lookAhead == rule2.lookAhead && rule1.firstNonSpace == rule2.firstNonSpace && rule1.context.context == rule2.context.context
|
||||||
&& rule1.endRegion == rule2.endRegion
|
&& rule1.context.popCount == rule2.context.popCount;
|
||||||
&& rule1.lookAhead == rule2.lookAhead
|
|
||||||
&& rule1.firstNonSpace == rule2.firstNonSpace
|
|
||||||
&& rule1.context.context == rule2.context.context
|
|
||||||
&& rule1.context.popCount == rule2.context.popCount
|
|
||||||
;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (rule1.type) {
|
switch (rule1.type) {
|
||||||
// request to merge AnyChar/DetectChar
|
// request to merge AnyChar/DetectChar
|
||||||
case Context::Rule::Type::AnyChar:
|
case Context::Rule::Type::AnyChar:
|
||||||
case Context::Rule::Type::DetectChar:
|
case Context::Rule::Type::DetectChar:
|
||||||
if ((rule2.type == Context::Rule::Type::AnyChar || rule2.type == Context::Rule::Type::DetectChar) && isCommonCompatible() && rule1.column == rule2.column) {
|
if ((rule2.type == Context::Rule::Type::AnyChar || rule2.type == Context::Rule::Type::DetectChar) && isCommonCompatible()
|
||||||
qWarning() << filename << "line" << rule2.line << "can be merged as AnyChar with the previous rule";
|
&& rule1.column == rule2.column) {
|
||||||
success = false;
|
qWarning() << filename << "line" << rule2.line << "can be merged as AnyChar with the previous rule";
|
||||||
}
|
success = false;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// request to merge multiple RegExpr
|
// request to merge multiple RegExpr
|
||||||
case Context::Rule::Type::RegExpr:
|
case Context::Rule::Type::RegExpr:
|
||||||
if (rule2.type == Context::Rule::Type::RegExpr && isCommonCompatible() && rule1.dynamic == rule2.dynamic && (rule1.column == rule2.column || (rule1.column <= 0 && rule2.column <= 0))) {
|
if (rule2.type == Context::Rule::Type::RegExpr && isCommonCompatible() && rule1.dynamic == rule2.dynamic
|
||||||
qWarning() << filename << "line" << rule2.line << "can be merged with the previous rule";
|
&& (rule1.column == rule2.column || (rule1.column <= 0 && rule2.column <= 0))) {
|
||||||
success = false;
|
qWarning() << filename << "line" << rule2.line << "can be merged with the previous rule";
|
||||||
}
|
success = false;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Context::Rule::Type::DetectSpaces:
|
case Context::Rule::Type::DetectSpaces:
|
||||||
case Context::Rule::Type::HlCChar:
|
case Context::Rule::Type::HlCChar:
|
||||||
case Context::Rule::Type::HlCHex:
|
case Context::Rule::Type::HlCHex:
|
||||||
case Context::Rule::Type::HlCOct:
|
case Context::Rule::Type::HlCOct:
|
||||||
case Context::Rule::Type::HlCStringChar:
|
case Context::Rule::Type::HlCStringChar:
|
||||||
case Context::Rule::Type::Int:
|
case Context::Rule::Type::Int:
|
||||||
case Context::Rule::Type::Float:
|
case Context::Rule::Type::Float:
|
||||||
case Context::Rule::Type::LineContinue:
|
case Context::Rule::Type::LineContinue:
|
||||||
case Context::Rule::Type::WordDetect:
|
case Context::Rule::Type::WordDetect:
|
||||||
case Context::Rule::Type::StringDetect:
|
case Context::Rule::Type::StringDetect:
|
||||||
case Context::Rule::Type::Detect2Chars:
|
case Context::Rule::Type::Detect2Chars:
|
||||||
case Context::Rule::Type::IncludeRules:
|
case Context::Rule::Type::IncludeRules:
|
||||||
case Context::Rule::Type::DetectIdentifier:
|
case Context::Rule::Type::DetectIdentifier:
|
||||||
case Context::Rule::Type::keyword:
|
case Context::Rule::Type::keyword:
|
||||||
case Context::Rule::Type::Unknown:
|
case Context::Rule::Type::Unknown:
|
||||||
case Context::Rule::Type::RangeDetect:
|
case Context::Rule::Type::RangeDetect:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@ target_sources(KF5SyntaxHighlighting PRIVATE
|
|||||||
context.cpp
|
context.cpp
|
||||||
contextswitch.cpp
|
contextswitch.cpp
|
||||||
definitiondownloader.cpp
|
definitiondownloader.cpp
|
||||||
|
highlightingdata.cpp
|
||||||
foldingregion.cpp
|
foldingregion.cpp
|
||||||
format.cpp
|
format.cpp
|
||||||
htmlhighlighter.cpp
|
htmlhighlighter.cpp
|
||||||
@@ -46,13 +47,13 @@ set_target_properties(KF5SyntaxHighlighting PROPERTIES
|
|||||||
SOVERSION ${SyntaxHighlighting_SOVERSION}
|
SOVERSION ${SyntaxHighlighting_SOVERSION}
|
||||||
EXPORT_NAME SyntaxHighlighting
|
EXPORT_NAME SyntaxHighlighting
|
||||||
)
|
)
|
||||||
target_include_directories(KF5SyntaxHighlighting INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting;${KDE_INSTALL_INCLUDEDIR_KF5}>")
|
target_include_directories(KF5SyntaxHighlighting INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting;${KDE_INSTALL_INCLUDEDIR_KF}>")
|
||||||
target_include_directories(KF5SyntaxHighlighting PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR};>")
|
target_include_directories(KF5SyntaxHighlighting PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR};>")
|
||||||
target_link_libraries(KF5SyntaxHighlighting
|
target_link_libraries(KF5SyntaxHighlighting
|
||||||
PUBLIC
|
PUBLIC
|
||||||
Qt5::Gui
|
Qt${QT_MAJOR_VERSION}::Gui
|
||||||
PRIVATE
|
PRIVATE
|
||||||
Qt5::Network
|
Qt${QT_MAJOR_VERSION}::Network
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_generate_headers(SyntaxHighlighting_HEADERS
|
ecm_generate_headers(SyntaxHighlighting_HEADERS
|
||||||
@@ -74,7 +75,7 @@ install(TARGETS KF5SyntaxHighlighting EXPORT KF5SyntaxHighlightingTargets ${KDE_
|
|||||||
install(FILES
|
install(FILES
|
||||||
${SyntaxHighlighting_HEADERS}
|
${SyntaxHighlighting_HEADERS}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_export.h
|
${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_export.h
|
||||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting)
|
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting)
|
||||||
|
|
||||||
if(BUILD_QCH)
|
if(BUILD_QCH)
|
||||||
ecm_add_qch(
|
ecm_add_qch(
|
||||||
@@ -104,6 +105,6 @@ ecm_generate_pri_file(
|
|||||||
KF5SyntaxHighlighting
|
KF5SyntaxHighlighting
|
||||||
DEPS "gui"
|
DEPS "gui"
|
||||||
FILENAME_VAR PRI_FILENAME
|
FILENAME_VAR PRI_FILENAME
|
||||||
INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting
|
INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting
|
||||||
)
|
)
|
||||||
install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
||||||
|
@@ -137,8 +137,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state)
|
|||||||
* see https://phabricator.kde.org/D18509
|
* see https://phabricator.kde.org/D18509
|
||||||
*/
|
*/
|
||||||
int endlessLoopingCounter = 0;
|
int endlessLoopingCounter = 0;
|
||||||
while (!stateData->topContext()->lineEmptyContext().isStay()
|
while (!stateData->topContext()->lineEmptyContext().isStay() || !stateData->topContext()->lineEndContext().isStay()) {
|
||||||
|| (stateData->topContext()->lineEmptyContext().isStay() && !stateData->topContext()->lineEndContext().isStay())) {
|
|
||||||
/**
|
/**
|
||||||
* line empty context switches
|
* line empty context switches
|
||||||
*/
|
*/
|
||||||
@@ -153,8 +152,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state)
|
|||||||
* line end context switches only when lineEmptyContext is #stay. This avoids
|
* line end context switches only when lineEmptyContext is #stay. This avoids
|
||||||
* skipping empty lines after a line continuation character (see bug 405903)
|
* skipping empty lines after a line continuation character (see bug 405903)
|
||||||
*/
|
*/
|
||||||
} else if (!stateData->topContext()->lineEndContext().isStay()
|
} else if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) {
|
||||||
&& !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +303,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state)
|
|||||||
|
|
||||||
d->switchContext(stateData, rule->context(), newResult.captures());
|
d->switchContext(stateData, rule->context(), newResult.captures());
|
||||||
newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat();
|
newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat();
|
||||||
if (newOffset == text.size() && std::dynamic_pointer_cast<LineContinue>(rule)) {
|
if (newOffset == text.size() && rule->isLineContinue()) {
|
||||||
lineContinuation = true;
|
lineContinuation = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QMap>
|
#include <QHash>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -539,7 +539,7 @@ double calculate_CIEDE2000(const CieLab &color1, const CieLab &color2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AnsiBuffer {
|
struct AnsiBuffer {
|
||||||
using ColorCache = QMap<QRgb, int>;
|
using ColorCache = QHash<QRgb, int>;
|
||||||
|
|
||||||
void append(char c)
|
void append(char c)
|
||||||
{
|
{
|
||||||
@@ -683,7 +683,8 @@ struct GraphLine {
|
|||||||
int labelLineLength = 0;
|
int labelLineLength = 0;
|
||||||
int nextLabelOffset = 0;
|
int nextLabelOffset = 0;
|
||||||
|
|
||||||
template<class String> void pushLabel(int offset, String const &s, int charCounter)
|
template<class String>
|
||||||
|
void pushLabel(int offset, String const &s, int charCounter)
|
||||||
{
|
{
|
||||||
Q_ASSERT(offset >= labelLineLength);
|
Q_ASSERT(offset >= labelLineLength);
|
||||||
const int n = offset - labelLineLength;
|
const int n = offset - labelLineLength;
|
||||||
@@ -693,7 +694,8 @@ struct GraphLine {
|
|||||||
nextLabelOffset = labelLineLength;
|
nextLabelOffset = labelLineLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class String> void pushGraph(int offset, String const &s, int charCounter)
|
template<class String>
|
||||||
|
void pushGraph(int offset, String const &s, int charCounter)
|
||||||
{
|
{
|
||||||
Q_ASSERT(offset >= graphLineLength);
|
Q_ASSERT(offset >= graphLineLength);
|
||||||
const int n = offset - graphLineLength;
|
const int n = offset - graphLineLength;
|
||||||
@@ -754,8 +756,15 @@ public:
|
|||||||
void setDefinition(const KSyntaxHighlighting::Definition &def) override
|
void setDefinition(const KSyntaxHighlighting::Definition &def) override
|
||||||
{
|
{
|
||||||
AbstractHighlighter::setDefinition(def);
|
AbstractHighlighter::setDefinition(def);
|
||||||
m_defData = DefinitionData::get(def);
|
|
||||||
m_contextCapture.setDefinition(def);
|
m_contextCapture.setDefinition(def);
|
||||||
|
|
||||||
|
const auto &definitions = def.includedDefinitions();
|
||||||
|
for (const auto &definition : definitions) {
|
||||||
|
const auto *defData = DefinitionData::get(definition);
|
||||||
|
for (const auto &context : defData->contexts) {
|
||||||
|
m_defDataBycontexts.insert(&context, defData);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void highlightData(QTextStream &in,
|
void highlightData(QTextStream &in,
|
||||||
@@ -928,8 +937,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto context = stateData->topContext();
|
const auto context = stateData->topContext();
|
||||||
const auto defData = DefinitionData::get(context->definition());
|
const auto defDataIt = m_defDataBycontexts.find(context);
|
||||||
const auto contextName = (defData != m_defData) ? QString(QLatin1Char('<') % defData->name % QLatin1Char('>')) : QString();
|
const auto contextName = (defDataIt != m_defDataBycontexts.end()) ? QString(QLatin1Char('<') % (*defDataIt)->name % QLatin1Char('>')) : QString();
|
||||||
return QString(label % contextName % QLatin1Char('[') % context->name() % QLatin1Char(']'));
|
return QString(label % contextName % QLatin1Char('[') % context->name() % QLatin1Char(']'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1128,12 +1137,13 @@ private:
|
|||||||
std::vector<HighlightFragment> m_highlightedFragments;
|
std::vector<HighlightFragment> m_highlightedFragments;
|
||||||
std::vector<GraphLine> m_formatGraph;
|
std::vector<GraphLine> m_formatGraph;
|
||||||
ContextCaptureHighlighter m_contextCapture;
|
ContextCaptureHighlighter m_contextCapture;
|
||||||
DefinitionData *m_defData;
|
|
||||||
|
|
||||||
int m_regionDepth = 0;
|
int m_regionDepth = 0;
|
||||||
std::vector<Region> m_regions;
|
std::vector<Region> m_regions;
|
||||||
std::vector<GraphLine> m_regionGraph;
|
std::vector<GraphLine> m_regionGraph;
|
||||||
std::vector<QStringView> m_regionStyles;
|
std::vector<QStringView> m_regionStyles;
|
||||||
|
|
||||||
|
QHash<const Context *, const DefinitionData *> m_defDataBycontexts;
|
||||||
};
|
};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
@@ -18,177 +18,111 @@
|
|||||||
|
|
||||||
using namespace KSyntaxHighlighting;
|
using namespace KSyntaxHighlighting;
|
||||||
|
|
||||||
Definition Context::definition() const
|
Context::Context(const DefinitionData &def, const HighlightingContextData &data)
|
||||||
|
: m_name(data.name)
|
||||||
|
, m_attributeFormat(data.attribute.isEmpty() ? Format() : def.formatByName(data.attribute))
|
||||||
|
, m_indentationBasedFolding(!data.noIndentationBasedFolding && def.indentationBasedFolding)
|
||||||
{
|
{
|
||||||
return m_def.definition();
|
if (!data.attribute.isEmpty() && !m_attributeFormat.isValid()) {
|
||||||
}
|
qCWarning(Log) << "Context: Unknown format" << data.attribute << "in context" << m_name << "of definition" << def.name;
|
||||||
|
}
|
||||||
void Context::setDefinition(const DefinitionRef &def)
|
|
||||||
{
|
|
||||||
m_def = def;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Context::indentationBasedFoldingEnabled() const
|
bool Context::indentationBasedFoldingEnabled() const
|
||||||
{
|
{
|
||||||
if (m_noIndentationBasedFolding) {
|
return m_indentationBasedFolding;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_def.definition().indentationBasedFoldingEnabled();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::load(QXmlStreamReader &reader)
|
void Context::resolveContexts(DefinitionData &def, const HighlightingContextData &data)
|
||||||
{
|
{
|
||||||
Q_ASSERT(reader.name() == QLatin1String("context"));
|
m_lineEndContext.resolve(def, data.lineEndContext);
|
||||||
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
|
m_lineEmptyContext.resolve(def, data.lineEmptyContext);
|
||||||
|
m_fallthroughContext.resolve(def, data.fallthroughContext);
|
||||||
m_name = reader.attributes().value(QLatin1String("name")).toString();
|
|
||||||
m_attribute = reader.attributes().value(QLatin1String("attribute")).toString();
|
|
||||||
m_lineEndContext.parse(reader.attributes().value(QLatin1String("lineEndContext")));
|
|
||||||
m_lineEmptyContext.parse(reader.attributes().value(QLatin1String("lineEmptyContext")));
|
|
||||||
m_fallthroughContext.parse(reader.attributes().value(QLatin1String("fallthroughContext")));
|
|
||||||
m_fallthrough = !m_fallthroughContext.isStay();
|
m_fallthrough = !m_fallthroughContext.isStay();
|
||||||
m_noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding")));
|
|
||||||
|
|
||||||
reader.readNext();
|
m_rules.reserve(data.rules.size());
|
||||||
while (!reader.atEnd()) {
|
for (const auto &ruleData : data.rules) {
|
||||||
switch (reader.tokenType()) {
|
m_rules.push_back(Rule::create(def, ruleData, m_name));
|
||||||
case QXmlStreamReader::StartElement: {
|
if (!m_rules.back()) {
|
||||||
auto rule = Rule::create(reader.name());
|
m_rules.pop_back();
|
||||||
if (rule) {
|
|
||||||
rule->setDefinition(m_def.definition());
|
|
||||||
if (rule->load(reader)) {
|
|
||||||
m_rules.push_back(std::move(rule));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reader.skipCurrentElement();
|
|
||||||
}
|
|
||||||
reader.readNext();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QXmlStreamReader::EndElement:
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
reader.readNext();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::resolveContexts()
|
void Context::resolveIncludes(DefinitionData &def)
|
||||||
{
|
{
|
||||||
const auto def = m_def.definition();
|
if (m_resolveState == Resolved) {
|
||||||
m_lineEndContext.resolve(def);
|
|
||||||
m_lineEmptyContext.resolve(def);
|
|
||||||
m_fallthroughContext.resolve(def);
|
|
||||||
for (const auto &rule : m_rules) {
|
|
||||||
rule->resolveContext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Context::ResolveState Context::resolveState()
|
|
||||||
{
|
|
||||||
if (m_resolveState == Unknown) {
|
|
||||||
for (const auto &rule : m_rules) {
|
|
||||||
auto inc = std::dynamic_pointer_cast<IncludeRules>(rule);
|
|
||||||
if (inc) {
|
|
||||||
m_resolveState = Unresolved;
|
|
||||||
return m_resolveState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_resolveState = Resolved;
|
|
||||||
}
|
|
||||||
return m_resolveState;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::resolveIncludes()
|
|
||||||
{
|
|
||||||
if (resolveState() == Resolved) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (resolveState() == Resolving) {
|
if (m_resolveState == Resolving) {
|
||||||
qCWarning(Log) << "Cyclic dependency!";
|
qCWarning(Log) << "Cyclic dependency!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(resolveState() == Unresolved);
|
Q_ASSERT(m_resolveState == Unresolved);
|
||||||
m_resolveState = Resolving; // cycle guard
|
m_resolveState = Resolving; // cycle guard
|
||||||
|
|
||||||
for (auto it = m_rules.begin(); it != m_rules.end();) {
|
for (auto it = m_rules.begin(); it != m_rules.end();) {
|
||||||
auto inc = std::dynamic_pointer_cast<IncludeRules>(*it);
|
const IncludeRules *includeRules = it->get()->castToIncludeRules();
|
||||||
if (!inc) {
|
if (!includeRules) {
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context *context = nullptr;
|
Context *context = nullptr;
|
||||||
auto myDefData = DefinitionData::get(m_def.definition());
|
DefinitionData *defData = &def;
|
||||||
if (inc->definitionName().isEmpty()) { // local include
|
|
||||||
context = myDefData->contextByName(inc->contextName());
|
const auto &contextName = includeRules->contextName();
|
||||||
|
const int idx = contextName.indexOf(QLatin1String("##"));
|
||||||
|
|
||||||
|
if (idx == -1) { // local include
|
||||||
|
context = def.contextByName(contextName);
|
||||||
} else {
|
} else {
|
||||||
auto def = myDefData->repo->definitionForName(inc->definitionName());
|
auto definitionName = contextName.mid(idx + 2);
|
||||||
if (!def.isValid()) {
|
auto includedDef = def.repo->definitionForName(definitionName);
|
||||||
qCWarning(Log) << "Unable to resolve external include rule for definition" << inc->definitionName() << "in" << m_def.definition().name();
|
if (!includedDef.isValid()) {
|
||||||
|
qCWarning(Log) << "Unable to resolve external include rule for definition" << definitionName << "in" << def.name;
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto defData = DefinitionData::get(def);
|
defData = DefinitionData::get(includedDef);
|
||||||
|
def.addImmediateIncludedDefinition(includedDef);
|
||||||
defData->load();
|
defData->load();
|
||||||
if (inc->contextName().isEmpty()) {
|
if (idx == 0) {
|
||||||
context = defData->initialContext();
|
context = defData->initialContext();
|
||||||
} else {
|
} else {
|
||||||
context = defData->contextByName(inc->contextName());
|
context = defData->contextByName(contextName.left(idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in"
|
qCWarning(Log) << "Unable to resolve include rule for definition" << contextName << "in" << def.name;
|
||||||
<< m_def.definition().name();
|
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
context->resolveIncludes();
|
|
||||||
|
if (context == this) {
|
||||||
|
qCWarning(Log) << "Unable to resolve self include rule for definition" << contextName << "in" << def.name;
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->m_resolveState != Resolved) {
|
||||||
|
context->resolveIncludes(*defData);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle included attribute
|
* handle included attribute
|
||||||
* transitive closure: we might include attributes included from somewhere else
|
* transitive closure: we might include attributes included from somewhere else
|
||||||
*/
|
*/
|
||||||
if (inc->includeAttribute()) {
|
if (includeRules->includeAttribute()) {
|
||||||
m_attribute = context->m_attribute;
|
m_attributeFormat = context->m_attributeFormat;
|
||||||
m_attributeContext = context->m_attributeContext ? context->m_attributeContext : context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it = m_rules.erase(it);
|
it = m_rules.erase(it);
|
||||||
for (const auto &rule : context->rules()) {
|
it = m_rules.insert(it, context->rules().begin(), context->rules().end());
|
||||||
it = m_rules.insert(it, rule);
|
it += context->rules().size();
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_resolveState = Resolved;
|
m_resolveState = Resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::resolveAttributeFormat()
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* try to get our format from the definition we stem from
|
|
||||||
* we need to handle included attributes via m_attributeContext
|
|
||||||
*/
|
|
||||||
if (!m_attribute.isEmpty()) {
|
|
||||||
const auto def = m_attributeContext ? m_attributeContext->m_def.definition() : m_def.definition();
|
|
||||||
m_attributeFormat = DefinitionData::get(def)->formatByName(m_attribute);
|
|
||||||
if (!m_attributeFormat.isValid()) {
|
|
||||||
if (m_attributeContext) {
|
|
||||||
qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name()
|
|
||||||
<< "from included context" << m_attributeContext->m_name << "of definition" << def.name();
|
|
||||||
} else {
|
|
||||||
qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* lookup formats for our rules
|
|
||||||
*/
|
|
||||||
for (const auto &rule : m_rules) {
|
|
||||||
rule->resolveAttributeFormat(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -8,9 +8,8 @@
|
|||||||
#define KSYNTAXHIGHLIGHTING_CONTEXT_P_H
|
#define KSYNTAXHIGHLIGHTING_CONTEXT_P_H
|
||||||
|
|
||||||
#include "contextswitch_p.h"
|
#include "contextswitch_p.h"
|
||||||
#include "definition.h"
|
|
||||||
#include "definitionref_p.h"
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
#include "highlightingdata_p.hpp"
|
||||||
#include "rule_p.h"
|
#include "rule_p.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@@ -23,14 +22,18 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace KSyntaxHighlighting
|
namespace KSyntaxHighlighting
|
||||||
{
|
{
|
||||||
|
class DefinitionData;
|
||||||
|
|
||||||
class Context
|
class Context
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Context() = default;
|
Q_DISABLE_COPY(Context)
|
||||||
~Context() = default;
|
|
||||||
|
|
||||||
Definition definition() const;
|
Context(Context &&) = default;
|
||||||
void setDefinition(const DefinitionRef &def);
|
Context &operator=(Context &&) = default;
|
||||||
|
|
||||||
|
Context(const DefinitionData &def, const HighlightingContextData &data);
|
||||||
|
~Context() = default;
|
||||||
|
|
||||||
const QString &name() const
|
const QString &name() const
|
||||||
{
|
{
|
||||||
@@ -73,44 +76,28 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool indentationBasedFoldingEnabled() const;
|
bool indentationBasedFoldingEnabled() const;
|
||||||
|
|
||||||
void load(QXmlStreamReader &reader);
|
void resolveContexts(DefinitionData &def, const HighlightingContextData &data);
|
||||||
void resolveContexts();
|
void resolveIncludes(DefinitionData &def);
|
||||||
void resolveIncludes();
|
|
||||||
void resolveAttributeFormat();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(Context)
|
enum ResolveState : quint8 { Unresolved, Resolving, Resolved };
|
||||||
|
|
||||||
enum ResolveState { Unknown, Unresolved, Resolving, Resolved };
|
std::vector<Rule::Ptr> m_rules;
|
||||||
ResolveState resolveState();
|
|
||||||
|
|
||||||
DefinitionRef m_def;
|
|
||||||
QString m_name;
|
QString m_name;
|
||||||
|
|
||||||
/**
|
|
||||||
* attribute name, to lookup our format
|
|
||||||
*/
|
|
||||||
QString m_attribute;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* context to use for lookup, if != this context
|
|
||||||
*/
|
|
||||||
const Context *m_attributeContext = nullptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* resolved format for our attribute, done in resolveAttributeFormat
|
|
||||||
*/
|
|
||||||
Format m_attributeFormat;
|
|
||||||
|
|
||||||
ContextSwitch m_lineEndContext;
|
ContextSwitch m_lineEndContext;
|
||||||
ContextSwitch m_lineEmptyContext;
|
ContextSwitch m_lineEmptyContext;
|
||||||
ContextSwitch m_fallthroughContext;
|
ContextSwitch m_fallthroughContext;
|
||||||
|
|
||||||
std::vector<Rule::Ptr> m_rules;
|
/**
|
||||||
|
* resolved format for our attribute, done in constructor and resolveIncludes
|
||||||
|
*/
|
||||||
|
Format m_attributeFormat;
|
||||||
|
|
||||||
ResolveState m_resolveState = Unknown;
|
ResolveState m_resolveState = Unresolved;
|
||||||
bool m_fallthrough = false;
|
bool m_fallthrough = false;
|
||||||
bool m_noIndentationBasedFolding = false;
|
bool m_indentationBasedFolding;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,69 +7,45 @@
|
|||||||
#include "contextswitch_p.h"
|
#include "contextswitch_p.h"
|
||||||
#include "definition.h"
|
#include "definition.h"
|
||||||
#include "definition_p.h"
|
#include "definition_p.h"
|
||||||
|
#include "highlightingdata_p.hpp"
|
||||||
#include "ksyntaxhighlighting_logging.h"
|
#include "ksyntaxhighlighting_logging.h"
|
||||||
#include "repository.h"
|
#include "repository.h"
|
||||||
|
|
||||||
using namespace KSyntaxHighlighting;
|
using namespace KSyntaxHighlighting;
|
||||||
|
|
||||||
bool ContextSwitch::isStay() const
|
void ContextSwitch::resolve(DefinitionData &def, QStringView contextInstr)
|
||||||
{
|
{
|
||||||
return m_popCount == 0 && !m_context && m_contextName.isEmpty() && m_defName.isEmpty();
|
HighlightingContextData::ContextSwitch ctx(contextInstr);
|
||||||
}
|
|
||||||
|
|
||||||
int ContextSwitch::popCount() const
|
m_popCount = ctx.popCount();
|
||||||
{
|
m_isStay = !m_popCount;
|
||||||
return m_popCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
Context *ContextSwitch::context() const
|
auto contextName = ctx.contextName();
|
||||||
{
|
auto defName = ctx.defName();
|
||||||
return m_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextSwitch::parse(QStringView contextInstr)
|
if (contextName.isEmpty() && defName.isEmpty()) {
|
||||||
{
|
|
||||||
if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay")) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contextInstr.startsWith(QLatin1String("#pop!"))) {
|
if (defName.isEmpty()) {
|
||||||
++m_popCount;
|
m_context = def.contextByName(contextName.toString());
|
||||||
m_contextName = contextInstr.mid(5).toString();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contextInstr.startsWith(QLatin1String("#pop"))) {
|
|
||||||
++m_popCount;
|
|
||||||
parse(contextInstr.mid(4));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto idx = contextInstr.indexOf(QLatin1String("##"));
|
|
||||||
if (idx >= 0) {
|
|
||||||
m_contextName = contextInstr.left(idx).toString();
|
|
||||||
m_defName = contextInstr.mid(idx + 2).toString();
|
|
||||||
} else {
|
} else {
|
||||||
m_contextName = contextInstr.toString();
|
auto d = def.repo->definitionForName(defName.toString());
|
||||||
}
|
if (d.isValid()) {
|
||||||
}
|
auto data = DefinitionData::get(d);
|
||||||
|
def.addImmediateIncludedDefinition(d);
|
||||||
void ContextSwitch::resolve(const Definition &def)
|
data->load();
|
||||||
{
|
if (contextName.isEmpty()) {
|
||||||
auto d = def;
|
m_context = data->initialContext();
|
||||||
if (!m_defName.isEmpty()) {
|
} else {
|
||||||
d = DefinitionData::get(def)->repo->definitionForName(m_defName);
|
m_context = data->contextByName(contextName.toString());
|
||||||
auto data = DefinitionData::get(d);
|
}
|
||||||
data->load();
|
|
||||||
if (m_contextName.isEmpty()) {
|
|
||||||
m_context = data->initialContext();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_contextName.isEmpty()) {
|
if (!m_context) {
|
||||||
m_context = DefinitionData::get(d)->contextByName(m_contextName);
|
qCWarning(Log) << "cannot find context" << contextName << "in" << def.name;
|
||||||
if (!m_context) {
|
} else {
|
||||||
qCWarning(Log) << "cannot find context" << m_contextName << "in" << def.name();
|
m_isStay = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
namespace KSyntaxHighlighting
|
namespace KSyntaxHighlighting
|
||||||
{
|
{
|
||||||
class Context;
|
class Context;
|
||||||
class Definition;
|
class DefinitionData;
|
||||||
|
|
||||||
class ContextSwitch
|
class ContextSwitch
|
||||||
{
|
{
|
||||||
@@ -20,19 +20,27 @@ public:
|
|||||||
ContextSwitch() = default;
|
ContextSwitch() = default;
|
||||||
~ContextSwitch() = default;
|
~ContextSwitch() = default;
|
||||||
|
|
||||||
bool isStay() const;
|
bool isStay() const
|
||||||
|
{
|
||||||
|
return m_isStay;
|
||||||
|
}
|
||||||
|
|
||||||
int popCount() const;
|
int popCount() const
|
||||||
Context *context() const;
|
{
|
||||||
|
return m_popCount;
|
||||||
|
}
|
||||||
|
|
||||||
void parse(QStringView contextInstr);
|
Context *context() const
|
||||||
void resolve(const Definition &def);
|
{
|
||||||
|
return m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolve(DefinitionData &def, QStringView contextInstr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_defName;
|
|
||||||
QString m_contextName;
|
|
||||||
Context *m_context = nullptr;
|
Context *m_context = nullptr;
|
||||||
int m_popCount = 0;
|
int m_popCount = 0;
|
||||||
|
bool m_isStay = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include "context_p.h"
|
#include "context_p.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "format_p.h"
|
#include "format_p.h"
|
||||||
|
#include "highlightingdata_p.hpp"
|
||||||
#include "ksyntaxhighlighting_logging.h"
|
#include "ksyntaxhighlighting_logging.h"
|
||||||
#include "ksyntaxhighlighting_version.h"
|
#include "ksyntaxhighlighting_version.h"
|
||||||
#include "repository.h"
|
#include "repository.h"
|
||||||
@@ -39,10 +40,7 @@ DefinitionData::DefinitionData()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
DefinitionData::~DefinitionData()
|
DefinitionData::~DefinitionData() = default;
|
||||||
{
|
|
||||||
qDeleteAll(contexts);
|
|
||||||
}
|
|
||||||
|
|
||||||
DefinitionData *DefinitionData::get(const Definition &def)
|
DefinitionData *DefinitionData::get(const Definition &def)
|
||||||
{
|
{
|
||||||
@@ -237,45 +235,23 @@ QVector<Definition> Definition::includedDefinitions() const
|
|||||||
d->load();
|
d->load();
|
||||||
|
|
||||||
// init worklist and result used as guard with this definition
|
// init worklist and result used as guard with this definition
|
||||||
QVector<Definition> queue{*this};
|
QVector<const DefinitionData *> queue{d.get()};
|
||||||
QVector<Definition> definitions{*this};
|
QVector<Definition> definitions{*this};
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.empty()) {
|
||||||
// Iterate all context rules to find associated Definitions. This will
|
const auto *def = queue.back();
|
||||||
// automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch.
|
queue.pop_back();
|
||||||
const auto definition = queue.takeLast();
|
for (const auto &defRef : def->immediateIncludedDefinitions) {
|
||||||
for (const auto &context : std::as_const(definition.d->contexts)) {
|
const auto definition = defRef.definition();
|
||||||
// handle context switch attributes of this context itself
|
if (!definitions.contains(definition)) {
|
||||||
for (const auto switchContext :
|
definitions.push_back(definition);
|
||||||
{context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) {
|
queue.push_back(definition.d.get());
|
||||||
if (switchContext) {
|
|
||||||
if (!definitions.contains(switchContext->definition())) {
|
|
||||||
queue.push_back(switchContext->definition());
|
|
||||||
definitions.push_back(switchContext->definition());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle the embedded rules
|
|
||||||
for (const auto &rule : context->rules()) {
|
|
||||||
// handle include rules like inclusion
|
|
||||||
if (!definitions.contains(rule->definition())) {
|
|
||||||
queue.push_back(rule->definition());
|
|
||||||
definitions.push_back(rule->definition());
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle context switch context inclusion
|
|
||||||
if (auto switchContext = rule->context().context()) {
|
|
||||||
if (!definitions.contains(switchContext->definition())) {
|
|
||||||
queue.push_back(switchContext->definition());
|
|
||||||
definitions.push_back(switchContext->definition());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the 1st entry, since it is this Definition
|
// remove the 1st entry, since it is this Definition
|
||||||
definitions.pop_front();
|
definitions.front() = std::move(definitions.back());
|
||||||
|
definitions.pop_back();
|
||||||
|
|
||||||
return definitions;
|
return definitions;
|
||||||
}
|
}
|
||||||
@@ -304,17 +280,17 @@ QVector<QPair<QChar, QString>> Definition::characterEncodings() const
|
|||||||
return d->characterEncodings;
|
return d->characterEncodings;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context *DefinitionData::initialContext() const
|
Context *DefinitionData::initialContext()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!contexts.isEmpty());
|
Q_ASSERT(!contexts.empty());
|
||||||
return contexts.first();
|
return &contexts.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
Context *DefinitionData::contextByName(const QString &wantedName) const
|
Context *DefinitionData::contextByName(const QString &wantedName)
|
||||||
{
|
{
|
||||||
for (const auto context : contexts) {
|
for (auto &context : contexts) {
|
||||||
if (context->name() == wantedName) {
|
if (context.name() == wantedName) {
|
||||||
return context;
|
return &context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -338,7 +314,7 @@ Format DefinitionData::formatByName(const QString &wantedName) const
|
|||||||
|
|
||||||
bool DefinitionData::isLoaded() const
|
bool DefinitionData::isLoaded() const
|
||||||
{
|
{
|
||||||
return !contexts.isEmpty();
|
return !contexts.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DefinitionData::load(OnlyKeywords onlyKeywords)
|
bool DefinitionData::load(OnlyKeywords onlyKeywords)
|
||||||
@@ -383,17 +359,7 @@ bool DefinitionData::load(OnlyKeywords onlyKeywords)
|
|||||||
it->setCaseSensitivity(caseSensitive);
|
it->setCaseSensitivity(caseSensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto context : std::as_const(contexts)) {
|
resolveContexts();
|
||||||
context->resolveContexts();
|
|
||||||
context->resolveIncludes();
|
|
||||||
context->resolveAttributeFormat();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto context : std::as_const(contexts)) {
|
|
||||||
for (const auto &rule : context->rules()) {
|
|
||||||
rule->resolvePostProcessing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -402,9 +368,21 @@ void DefinitionData::clear()
|
|||||||
{
|
{
|
||||||
// keep only name and repo, so we can re-lookup to make references persist over repo reloads
|
// keep only name and repo, so we can re-lookup to make references persist over repo reloads
|
||||||
keywordLists.clear();
|
keywordLists.clear();
|
||||||
qDeleteAll(contexts);
|
|
||||||
contexts.clear();
|
contexts.clear();
|
||||||
formats.clear();
|
formats.clear();
|
||||||
|
contextDatas.clear();
|
||||||
|
immediateIncludedDefinitions.clear();
|
||||||
|
wordDelimiters = WordDelimiters();
|
||||||
|
wordWrapDelimiters = wordDelimiters;
|
||||||
|
keywordIsLoaded = false;
|
||||||
|
hasFoldingRegions = false;
|
||||||
|
indentationBasedFolding = false;
|
||||||
|
foldingIgnoreList.clear();
|
||||||
|
singleLineCommentMarker.clear();
|
||||||
|
singleLineCommentPosition = CommentPosition::StartOfLine;
|
||||||
|
multiLineCommentStartMarker.clear();
|
||||||
|
multiLineCommentEndMarker.clear();
|
||||||
|
characterEncodings.clear();
|
||||||
|
|
||||||
fileName.clear();
|
fileName.clear();
|
||||||
section.clear();
|
section.clear();
|
||||||
@@ -414,8 +392,6 @@ void DefinitionData::clear()
|
|||||||
license.clear();
|
license.clear();
|
||||||
mimetypes.clear();
|
mimetypes.clear();
|
||||||
extensions.clear();
|
extensions.clear();
|
||||||
wordDelimiters = WordDelimiters();
|
|
||||||
wordWrapDelimiters = wordDelimiters;
|
|
||||||
caseSensitive = Qt::CaseSensitive;
|
caseSensitive = Qt::CaseSensitive;
|
||||||
version = 0.0f;
|
version = 0.0f;
|
||||||
priority = 0;
|
priority = 0;
|
||||||
@@ -563,14 +539,14 @@ void DefinitionData::loadContexts(QXmlStreamReader &reader)
|
|||||||
Q_ASSERT(reader.name() == QLatin1String("contexts"));
|
Q_ASSERT(reader.name() == QLatin1String("contexts"));
|
||||||
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
|
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
|
||||||
|
|
||||||
|
contextDatas.reserve(32);
|
||||||
|
|
||||||
while (!reader.atEnd()) {
|
while (!reader.atEnd()) {
|
||||||
switch (reader.tokenType()) {
|
switch (reader.tokenType()) {
|
||||||
case QXmlStreamReader::StartElement:
|
case QXmlStreamReader::StartElement:
|
||||||
if (reader.name() == QLatin1String("context")) {
|
if (reader.name() == QLatin1String("context")) {
|
||||||
auto context = new Context;
|
contextDatas.push_back(HighlightingContextData());
|
||||||
context->setDefinition(q);
|
contextDatas.back().load(name, reader);
|
||||||
context->load(reader);
|
|
||||||
contexts.push_back(context);
|
|
||||||
}
|
}
|
||||||
reader.readNext();
|
reader.readNext();
|
||||||
break;
|
break;
|
||||||
@@ -583,6 +559,50 @@ void DefinitionData::loadContexts(QXmlStreamReader &reader)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefinitionData::resolveContexts()
|
||||||
|
{
|
||||||
|
contexts.reserve(contextDatas.size());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform all HighlightingContextData to Context.
|
||||||
|
* This is necessary so that Context::resolveContexts() can find the referenced contexts.
|
||||||
|
*/
|
||||||
|
for (const auto &contextData : std::as_const(contextDatas)) {
|
||||||
|
contexts.emplace_back(*this, contextData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves contexts and rules.
|
||||||
|
*/
|
||||||
|
auto ctxIt = contexts.begin();
|
||||||
|
for (const auto &contextData : std::as_const(contextDatas)) {
|
||||||
|
ctxIt->resolveContexts(*this, contextData);
|
||||||
|
++ctxIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To free the memory, constDatas is emptied because it is no longer used.
|
||||||
|
*/
|
||||||
|
contextDatas.clear();
|
||||||
|
contextDatas.shrink_to_fit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolved includeRules.
|
||||||
|
*/
|
||||||
|
for (auto &context : contexts) {
|
||||||
|
context.resolveIncludes(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post-processing on rules.
|
||||||
|
*/
|
||||||
|
for (const auto &context : contexts) {
|
||||||
|
for (auto &rule : context.rules()) {
|
||||||
|
rule->resolvePostProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DefinitionData::loadItemData(QXmlStreamReader &reader)
|
void DefinitionData::loadItemData(QXmlStreamReader &reader)
|
||||||
{
|
{
|
||||||
Q_ASSERT(reader.name() == QLatin1String("itemDatas"));
|
Q_ASSERT(reader.name() == QLatin1String("itemDatas"));
|
||||||
@@ -635,8 +655,7 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader)
|
|||||||
wordDelimiters.remove(reader.attributes().value(QLatin1String("weakDeliminator")));
|
wordDelimiters.remove(reader.attributes().value(QLatin1String("weakDeliminator")));
|
||||||
|
|
||||||
// adapt WordWrapDelimiters
|
// adapt WordWrapDelimiters
|
||||||
auto wordWrapDeliminatorAttr = reader.attributes().value(
|
auto wordWrapDeliminatorAttr = reader.attributes().value(QLatin1String("wordWrapDeliminator"));
|
||||||
QLatin1String("wordWrapDeliminator"));
|
|
||||||
if (wordWrapDeliminatorAttr.isEmpty()) {
|
if (wordWrapDeliminatorAttr.isEmpty()) {
|
||||||
wordWrapDelimiters = wordDelimiters;
|
wordWrapDelimiters = wordDelimiters;
|
||||||
} else {
|
} else {
|
||||||
@@ -803,21 +822,40 @@ quint16 DefinitionData::foldingRegionId(const QString &foldName)
|
|||||||
return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName);
|
return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefinitionRef::DefinitionRef()
|
void DefinitionData::addImmediateIncludedDefinition(const Definition &def)
|
||||||
{
|
{
|
||||||
|
if (get(def) != this) {
|
||||||
|
DefinitionRef defRef(def);
|
||||||
|
if (!immediateIncludedDefinitions.contains(defRef)) {
|
||||||
|
immediateIncludedDefinitions.push_back(std::move(defRef));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefinitionRef::DefinitionRef() = default;
|
||||||
|
|
||||||
DefinitionRef::DefinitionRef(const Definition &def)
|
DefinitionRef::DefinitionRef(const Definition &def)
|
||||||
: d(def.d)
|
: d(def.d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefinitionRef::DefinitionRef(Definition &&def)
|
||||||
|
: d(std::move(def.d))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
DefinitionRef &DefinitionRef::operator=(const Definition &def)
|
DefinitionRef &DefinitionRef::operator=(const Definition &def)
|
||||||
{
|
{
|
||||||
d = def.d;
|
d = def.d;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefinitionRef &DefinitionRef::operator=(Definition &&def)
|
||||||
|
{
|
||||||
|
d = std::move(def.d);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Definition DefinitionRef::definition() const
|
Definition DefinitionRef::definition() const
|
||||||
{
|
{
|
||||||
if (!d.expired()) {
|
if (!d.expired()) {
|
||||||
@@ -828,9 +866,5 @@ Definition DefinitionRef::definition() const
|
|||||||
|
|
||||||
bool DefinitionRef::operator==(const DefinitionRef &other) const
|
bool DefinitionRef::operator==(const DefinitionRef &other) const
|
||||||
{
|
{
|
||||||
if (d.expired() != other.d.expired()) {
|
return !d.owner_before(other.d) && !other.d.owner_before(d);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.expired() || d.lock().get() == other.d.lock().get();
|
|
||||||
}
|
}
|
||||||
|
@@ -8,14 +8,16 @@
|
|||||||
#ifndef KSYNTAXHIGHLIGHTING_DEFINITION_P_H
|
#ifndef KSYNTAXHIGHLIGHTING_DEFINITION_P_H
|
||||||
#define KSYNTAXHIGHLIGHTING_DEFINITION_P_H
|
#define KSYNTAXHIGHLIGHTING_DEFINITION_P_H
|
||||||
|
|
||||||
#include "definition.h"
|
|
||||||
#include "definitionref_p.h"
|
#include "definitionref_p.h"
|
||||||
|
#include "highlightingdata_p.hpp"
|
||||||
#include "worddelimiters_p.h"
|
#include "worddelimiters_p.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QCborMap;
|
class QCborMap;
|
||||||
class QXmlStreamReader;
|
class QXmlStreamReader;
|
||||||
@@ -55,23 +57,31 @@ public:
|
|||||||
void loadSpellchecking(QXmlStreamReader &reader);
|
void loadSpellchecking(QXmlStreamReader &reader);
|
||||||
bool checkKateVersion(QStringView verStr);
|
bool checkKateVersion(QStringView verStr);
|
||||||
|
|
||||||
|
void resolveContexts();
|
||||||
|
|
||||||
void resolveIncludeKeywords();
|
void resolveIncludeKeywords();
|
||||||
|
|
||||||
KeywordList *keywordList(const QString &name);
|
KeywordList *keywordList(const QString &name);
|
||||||
|
|
||||||
Context *initialContext() const;
|
Context *initialContext();
|
||||||
Context *contextByName(const QString &name) const;
|
Context *contextByName(const QString &name);
|
||||||
|
|
||||||
Format formatByName(const QString &name) const;
|
Format formatByName(const QString &name) const;
|
||||||
|
|
||||||
quint16 foldingRegionId(const QString &foldName);
|
quint16 foldingRegionId(const QString &foldName);
|
||||||
|
|
||||||
|
void addImmediateIncludedDefinition(const Definition &def);
|
||||||
|
|
||||||
DefinitionRef q;
|
DefinitionRef q;
|
||||||
|
|
||||||
Repository *repo = nullptr;
|
Repository *repo = nullptr;
|
||||||
QHash<QString, KeywordList> keywordLists;
|
QHash<QString, KeywordList> keywordLists;
|
||||||
QVector<Context *> contexts;
|
std::vector<Context> contexts;
|
||||||
QHash<QString, Format> formats;
|
QHash<QString, Format> formats;
|
||||||
|
// data loaded from xml file and emptied after loading contexts
|
||||||
|
QVector<HighlightingContextData> contextDatas;
|
||||||
|
// Definition referenced by IncludeRules and ContextSwitch
|
||||||
|
QVector<DefinitionRef> immediateIncludedDefinitions;
|
||||||
WordDelimiters wordDelimiters;
|
WordDelimiters wordDelimiters;
|
||||||
WordDelimiters wordWrapDelimiters;
|
WordDelimiters wordWrapDelimiters;
|
||||||
bool keywordIsLoaded = false;
|
bool keywordIsLoaded = false;
|
||||||
|
@@ -172,8 +172,7 @@ void DefinitionDownloader::start()
|
|||||||
const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(SyntaxHighlighting_VERSION_MAJOR) + QLatin1Char('.')
|
const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(SyntaxHighlighting_VERSION_MAJOR) + QLatin1Char('.')
|
||||||
+ QString::number(SyntaxHighlighting_VERSION_MINOR) + QLatin1String(".xml");
|
+ QString::number(SyntaxHighlighting_VERSION_MINOR) + QLatin1String(".xml");
|
||||||
auto req = QNetworkRequest(QUrl(url));
|
auto req = QNetworkRequest(QUrl(url));
|
||||||
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
|
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||||
QNetworkRequest::NoLessSafeRedirectPolicy);
|
|
||||||
auto reply = d->nam->get(req);
|
auto reply = d->nam->get(req);
|
||||||
QObject::connect(reply, &QNetworkReply::finished, this, [=]() {
|
QObject::connect(reply, &QNetworkReply::finished, this, [=]() {
|
||||||
d->definitionListDownloadFinished(reply);
|
d->definitionListDownloadFinished(reply);
|
||||||
|
@@ -59,7 +59,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
~DefinitionDownloader();
|
~DefinitionDownloader() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the update procedure.
|
* Starts the update procedure.
|
||||||
|
@@ -7,6 +7,8 @@
|
|||||||
#ifndef KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
|
#ifndef KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
|
||||||
#define KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
|
#define KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
|
||||||
|
|
||||||
|
#include "definition.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace KSyntaxHighlighting
|
namespace KSyntaxHighlighting
|
||||||
@@ -29,7 +31,9 @@ class DefinitionRef
|
|||||||
public:
|
public:
|
||||||
DefinitionRef();
|
DefinitionRef();
|
||||||
explicit DefinitionRef(const Definition &def);
|
explicit DefinitionRef(const Definition &def);
|
||||||
|
explicit DefinitionRef(Definition &&def);
|
||||||
DefinitionRef &operator=(const Definition &def);
|
DefinitionRef &operator=(const Definition &def);
|
||||||
|
DefinitionRef &operator=(Definition &&def);
|
||||||
|
|
||||||
Definition definition() const;
|
Definition definition() const;
|
||||||
|
|
||||||
|
402
src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp
vendored
Normal file
402
src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp
vendored
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2021 Jonathan Poelen <jonathan.poelen@gmail.com>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "highlightingdata_p.hpp"
|
||||||
|
#include "ksyntaxhighlighting_logging.h"
|
||||||
|
#include "xml_p.h"
|
||||||
|
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QStringView>
|
||||||
|
|
||||||
|
using namespace KSyntaxHighlighting;
|
||||||
|
|
||||||
|
template<class Data, class... Args>
|
||||||
|
static void initRuleData(Data &data, Args &&...args)
|
||||||
|
{
|
||||||
|
new (&data) Data{std::move(args)...};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Qt::CaseSensitivity attrToCaseSensitivity(QStringView str)
|
||||||
|
{
|
||||||
|
return Xml::attrToBool(str) ? Qt::CaseInsensitive : Qt::CaseSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HighlightingContextData::Rule::WordDelimiters loadAdditionalWordDelimiters(QXmlStreamReader &reader)
|
||||||
|
{
|
||||||
|
return HighlightingContextData::Rule::WordDelimiters{
|
||||||
|
reader.attributes().value(QLatin1String("additionalDeliminator")).toString(),
|
||||||
|
reader.attributes().value(QLatin1String("weakDeliminator")).toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkIsNotEmpty(QStringView str, const char *attrName, const QString &defName, QXmlStreamReader &reader)
|
||||||
|
{
|
||||||
|
if (!str.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCWarning(Log) << defName << "at line" << reader.lineNumber() << ": " << attrName << "attribute is empty";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkIsChar(QStringView str, const char *attrName, const QString &defName, QXmlStreamReader &reader)
|
||||||
|
{
|
||||||
|
if (str.size() == 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCWarning(Log) << defName << "at line" << reader.lineNumber() << ": " << attrName << "attribute must contain exactly 1 character";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool loadRule(const QString &defName, HighlightingContextData::Rule &rule, QXmlStreamReader &reader)
|
||||||
|
{
|
||||||
|
using Rule = HighlightingContextData::Rule;
|
||||||
|
|
||||||
|
QStringView name = reader.name();
|
||||||
|
const auto attrs = reader.attributes();
|
||||||
|
bool isIncludeRules = false;
|
||||||
|
|
||||||
|
if (name == QLatin1String("DetectChar")) {
|
||||||
|
const auto s = attrs.value(QLatin1String("char"));
|
||||||
|
if (!checkIsChar(s, "char", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const QChar c = s.at(0);
|
||||||
|
const bool dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic")));
|
||||||
|
|
||||||
|
initRuleData(rule.data.detectChar, c, dynamic);
|
||||||
|
rule.type = Rule::Type::DetectChar;
|
||||||
|
} else if (name == QLatin1String("RegExpr")) {
|
||||||
|
const auto pattern = attrs.value(QLatin1String("String"));
|
||||||
|
if (!checkIsNotEmpty(pattern, "String", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto isCaseInsensitive = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive")));
|
||||||
|
const auto isMinimal = Xml::attrToBool(attrs.value(QLatin1String("minimal")));
|
||||||
|
const auto dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic")));
|
||||||
|
|
||||||
|
initRuleData(rule.data.regExpr, pattern.toString(), isCaseInsensitive, isMinimal, dynamic);
|
||||||
|
rule.type = Rule::Type::RegExpr;
|
||||||
|
} else if (name == QLatin1String("IncludeRules")) {
|
||||||
|
const auto context = attrs.value(QLatin1String("context"));
|
||||||
|
if (!checkIsNotEmpty(context, "context", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const bool includeAttribute = Xml::attrToBool(attrs.value(QLatin1String("includeAttrib")));
|
||||||
|
|
||||||
|
initRuleData(rule.data.includeRules, context.toString(), includeAttribute);
|
||||||
|
rule.type = Rule::Type::IncludeRules;
|
||||||
|
isIncludeRules = true;
|
||||||
|
} else if (name == QLatin1String("Detect2Chars")) {
|
||||||
|
const auto s1 = attrs.value(QLatin1String("char"));
|
||||||
|
const auto s2 = attrs.value(QLatin1String("char1"));
|
||||||
|
if (!checkIsChar(s1, "char", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!checkIsChar(s2, "char1", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
initRuleData(rule.data.detect2Chars, s1.at(0), s2.at(0));
|
||||||
|
rule.type = Rule::Type::Detect2Chars;
|
||||||
|
} else if (name == QLatin1String("keyword")) {
|
||||||
|
const auto s = attrs.value(QLatin1String("String"));
|
||||||
|
if (!checkIsNotEmpty(s, "String", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Qt::CaseSensitivity caseSensitivityOverride = Qt::CaseInsensitive;
|
||||||
|
bool hasCaseSensitivityOverride = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* we might overwrite the case sensitivity
|
||||||
|
* then we need to init the list for lookup of that sensitivity setting
|
||||||
|
*/
|
||||||
|
if (attrs.hasAttribute(QLatin1String("insensitive"))) {
|
||||||
|
hasCaseSensitivityOverride = true;
|
||||||
|
caseSensitivityOverride = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive")));
|
||||||
|
}
|
||||||
|
|
||||||
|
initRuleData(rule.data.keyword, s.toString(), loadAdditionalWordDelimiters(reader), caseSensitivityOverride, hasCaseSensitivityOverride);
|
||||||
|
rule.type = Rule::Type::Keyword;
|
||||||
|
} else if (name == QLatin1String("DetectSpaces")) {
|
||||||
|
rule.type = Rule::Type::DetectSpaces;
|
||||||
|
} else if (name == QLatin1String("StringDetect")) {
|
||||||
|
const auto string = attrs.value(QLatin1String("String"));
|
||||||
|
if (!checkIsNotEmpty(string, "String", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto caseSensitivity = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive")));
|
||||||
|
const auto dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic")));
|
||||||
|
const bool isSensitive = (caseSensitivity == Qt::CaseSensitive);
|
||||||
|
|
||||||
|
// String can be replaced with DetectChar or AnyChar
|
||||||
|
if (!dynamic && string.size() == 1) {
|
||||||
|
QChar c = string.at(0);
|
||||||
|
if (isSensitive || c.toLower() == c.toUpper()) {
|
||||||
|
initRuleData(rule.data.detectChar, c, dynamic);
|
||||||
|
rule.type = Rule::Type::DetectChar;
|
||||||
|
} else {
|
||||||
|
initRuleData(rule.data.anyChar, c.toLower() + c.toUpper());
|
||||||
|
rule.type = Rule::Type::AnyChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// String can be replaced with Detect2Chars
|
||||||
|
else if (isSensitive && !dynamic && string.size() == 2) {
|
||||||
|
initRuleData(rule.data.detect2Chars, string.at(0), string.at(1));
|
||||||
|
rule.type = Rule::Type::Detect2Chars;
|
||||||
|
} else {
|
||||||
|
initRuleData(rule.data.stringDetect, string.toString(), caseSensitivity, dynamic);
|
||||||
|
rule.type = Rule::Type::StringDetect;
|
||||||
|
}
|
||||||
|
} else if (name == QLatin1String("WordDetect")) {
|
||||||
|
const auto word = attrs.value(QLatin1String("String"));
|
||||||
|
if (!checkIsNotEmpty(word, "String", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto caseSensitivity = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive")));
|
||||||
|
|
||||||
|
initRuleData(rule.data.wordDetect, word.toString(), loadAdditionalWordDelimiters(reader), caseSensitivity);
|
||||||
|
rule.type = Rule::Type::WordDetect;
|
||||||
|
} else if (name == QLatin1String("AnyChar")) {
|
||||||
|
const auto chars = attrs.value(QLatin1String("String"));
|
||||||
|
if (!checkIsNotEmpty(chars, "String", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnyChar can be replaced with DetectChar
|
||||||
|
if (chars.size() == 1) {
|
||||||
|
initRuleData(rule.data.detectChar, chars.at(0), false);
|
||||||
|
rule.type = Rule::Type::DetectChar;
|
||||||
|
} else {
|
||||||
|
initRuleData(rule.data.anyChar, chars.toString());
|
||||||
|
rule.type = Rule::Type::AnyChar;
|
||||||
|
}
|
||||||
|
} else if (name == QLatin1String("DetectIdentifier")) {
|
||||||
|
rule.type = Rule::Type::DetectIdentifier;
|
||||||
|
} else if (name == QLatin1String("LineContinue")) {
|
||||||
|
const auto s = attrs.value(QLatin1String("char"));
|
||||||
|
const QChar c = s.isEmpty() ? QLatin1Char('\\') : s.at(0);
|
||||||
|
|
||||||
|
initRuleData(rule.data.lineContinue, c);
|
||||||
|
rule.type = Rule::Type::LineContinue;
|
||||||
|
} else if (name == QLatin1String("Int")) {
|
||||||
|
initRuleData(rule.data.detectInt, loadAdditionalWordDelimiters(reader));
|
||||||
|
rule.type = Rule::Type::Int;
|
||||||
|
} else if (name == QLatin1String("Float")) {
|
||||||
|
initRuleData(rule.data.detectFloat, loadAdditionalWordDelimiters(reader));
|
||||||
|
rule.type = Rule::Type::Float;
|
||||||
|
} else if (name == QLatin1String("HlCStringChar")) {
|
||||||
|
rule.type = Rule::Type::HlCStringChar;
|
||||||
|
} else if (name == QLatin1String("RangeDetect")) {
|
||||||
|
const auto s1 = attrs.value(QLatin1String("char"));
|
||||||
|
const auto s2 = attrs.value(QLatin1String("char1"));
|
||||||
|
if (!checkIsChar(s1, "char", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!checkIsChar(s2, "char1", defName, reader)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
initRuleData(rule.data.rangeDetect, s1.at(0), s2.at(0));
|
||||||
|
rule.type = Rule::Type::RangeDetect;
|
||||||
|
} else if (name == QLatin1String("HlCHex")) {
|
||||||
|
initRuleData(rule.data.hlCHex, loadAdditionalWordDelimiters(reader));
|
||||||
|
rule.type = Rule::Type::HlCHex;
|
||||||
|
} else if (name == QLatin1String("HlCChar")) {
|
||||||
|
rule.type = Rule::Type::HlCChar;
|
||||||
|
} else if (name == QLatin1String("HlCOct")) {
|
||||||
|
initRuleData(rule.data.hlCOct, loadAdditionalWordDelimiters(reader));
|
||||||
|
rule.type = Rule::Type::HlCOct;
|
||||||
|
} else {
|
||||||
|
qCWarning(Log) << "Unknown rule type:" << name;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isIncludeRules) {
|
||||||
|
rule.common.contextName = attrs.value(QLatin1String("context")).toString();
|
||||||
|
rule.common.beginRegionName = attrs.value(QLatin1String("beginRegion")).toString();
|
||||||
|
rule.common.endRegionName = attrs.value(QLatin1String("endRegion")).toString();
|
||||||
|
rule.common.attributeName = attrs.value(QLatin1String("attribute")).toString();
|
||||||
|
rule.common.firstNonSpace = Xml::attrToBool(attrs.value(QLatin1String("firstNonSpace")));
|
||||||
|
rule.common.lookAhead = Xml::attrToBool(attrs.value(QLatin1String("lookAhead")));
|
||||||
|
bool colOk = false;
|
||||||
|
rule.common.column = attrs.value(QLatin1String("column")).toInt(&colOk);
|
||||||
|
if (!colOk) {
|
||||||
|
rule.common.column = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Data1, class Data2, class Visitor>
|
||||||
|
static void dataRuleVisit(HighlightingContextData::Rule::Type type, Data1 &&data1, Data2 &&data2, Visitor &&visitor)
|
||||||
|
{
|
||||||
|
using Rule = HighlightingContextData::Rule;
|
||||||
|
using Type = Rule::Type;
|
||||||
|
switch (type) {
|
||||||
|
case Type::AnyChar:
|
||||||
|
visitor(data1.anyChar, data2.anyChar);
|
||||||
|
break;
|
||||||
|
case Type::DetectChar:
|
||||||
|
visitor(data1.detectChar, data2.detectChar);
|
||||||
|
break;
|
||||||
|
case Type::Detect2Chars:
|
||||||
|
visitor(data1.detect2Chars, data2.detect2Chars);
|
||||||
|
break;
|
||||||
|
case Type::HlCOct:
|
||||||
|
visitor(data1.hlCOct, data2.hlCOct);
|
||||||
|
break;
|
||||||
|
case Type::IncludeRules:
|
||||||
|
visitor(data1.includeRules, data2.includeRules);
|
||||||
|
break;
|
||||||
|
case Type::Int:
|
||||||
|
visitor(data1.detectInt, data2.detectInt);
|
||||||
|
break;
|
||||||
|
case Type::Keyword:
|
||||||
|
visitor(data1.keyword, data2.keyword);
|
||||||
|
break;
|
||||||
|
case Type::LineContinue:
|
||||||
|
visitor(data1.lineContinue, data2.lineContinue);
|
||||||
|
break;
|
||||||
|
case Type::RangeDetect:
|
||||||
|
visitor(data1.rangeDetect, data2.rangeDetect);
|
||||||
|
break;
|
||||||
|
case Type::RegExpr:
|
||||||
|
visitor(data1.regExpr, data2.regExpr);
|
||||||
|
break;
|
||||||
|
case Type::StringDetect:
|
||||||
|
visitor(data1.stringDetect, data2.stringDetect);
|
||||||
|
break;
|
||||||
|
case Type::WordDetect:
|
||||||
|
visitor(data1.wordDetect, data2.wordDetect);
|
||||||
|
break;
|
||||||
|
case Type::Float:
|
||||||
|
visitor(data1.detectFloat, data2.detectFloat);
|
||||||
|
break;
|
||||||
|
case Type::HlCHex:
|
||||||
|
visitor(data1.hlCHex, data2.hlCHex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Type::HlCStringChar:
|
||||||
|
case Type::DetectIdentifier:
|
||||||
|
case Type::DetectSpaces:
|
||||||
|
case Type::HlCChar:
|
||||||
|
case Type::Unknown:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HighlightingContextData::Rule::Rule() noexcept = default;
|
||||||
|
|
||||||
|
HighlightingContextData::Rule::Rule(Rule &&other) noexcept
|
||||||
|
: common(std::move(other.common))
|
||||||
|
{
|
||||||
|
dataRuleVisit(other.type, data, other.data, [](auto &data1, auto &data2) {
|
||||||
|
using Data = std::remove_reference_t<decltype(data1)>;
|
||||||
|
new (&data1) Data(std::move(data2));
|
||||||
|
});
|
||||||
|
type = other.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
HighlightingContextData::Rule::Rule(const Rule &other)
|
||||||
|
: common(other.common)
|
||||||
|
{
|
||||||
|
dataRuleVisit(other.type, data, other.data, [](auto &data1, auto &data2) {
|
||||||
|
using Data = std::remove_reference_t<decltype(data1)>;
|
||||||
|
new (&data1) Data(data2);
|
||||||
|
});
|
||||||
|
type = other.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
HighlightingContextData::Rule::~Rule()
|
||||||
|
{
|
||||||
|
dataRuleVisit(type, data, data, [](auto &data, auto &) {
|
||||||
|
using Data = std::remove_reference_t<decltype(data)>;
|
||||||
|
data.~Data();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HighlightingContextData::ContextSwitch::ContextSwitch(QStringView str)
|
||||||
|
{
|
||||||
|
if (str.isEmpty() || str == QStringLiteral("#stay")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (str.startsWith(QStringLiteral("#pop"))) {
|
||||||
|
++m_popCount;
|
||||||
|
if (str.size() > 4 && str.at(4) == QLatin1Char('!')) {
|
||||||
|
str = str.mid(5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str = str.mid(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_contextAndDefName = str.toString();
|
||||||
|
m_defNameIndex = str.indexOf(QStringLiteral("##"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HighlightingContextData::ContextSwitch::isStay() const
|
||||||
|
{
|
||||||
|
return m_popCount == -1 && m_contextAndDefName.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringView HighlightingContextData::ContextSwitch::contextName() const
|
||||||
|
{
|
||||||
|
if (m_defNameIndex == -1) {
|
||||||
|
return m_contextAndDefName;
|
||||||
|
}
|
||||||
|
return QStringView(m_contextAndDefName).left(m_defNameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringView HighlightingContextData::ContextSwitch::defName() const
|
||||||
|
{
|
||||||
|
if (m_defNameIndex == -1) {
|
||||||
|
return QStringView();
|
||||||
|
}
|
||||||
|
return QStringView(m_contextAndDefName).mid(m_defNameIndex + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HighlightingContextData::load(const QString &defName, QXmlStreamReader &reader)
|
||||||
|
{
|
||||||
|
Q_ASSERT(reader.name() == QLatin1String("context"));
|
||||||
|
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
|
||||||
|
|
||||||
|
name = reader.attributes().value(QLatin1String("name")).toString();
|
||||||
|
attribute = reader.attributes().value(QLatin1String("attribute")).toString();
|
||||||
|
lineEndContext = reader.attributes().value(QLatin1String("lineEndContext")).toString();
|
||||||
|
lineEmptyContext = reader.attributes().value(QLatin1String("lineEmptyContext")).toString();
|
||||||
|
fallthroughContext = reader.attributes().value(QLatin1String("fallthroughContext")).toString();
|
||||||
|
noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding")));
|
||||||
|
|
||||||
|
rules.reserve(8);
|
||||||
|
|
||||||
|
reader.readNext();
|
||||||
|
while (!reader.atEnd()) {
|
||||||
|
switch (reader.tokenType()) {
|
||||||
|
case QXmlStreamReader::StartElement: {
|
||||||
|
auto &rule = rules.emplace_back();
|
||||||
|
if (!loadRule(defName, rule, reader)) {
|
||||||
|
rules.pop_back();
|
||||||
|
}
|
||||||
|
// be done with this rule, skip all subelements, e.g. no longer supported sub-rules
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
reader.readNext();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QXmlStreamReader::EndElement:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
reader.readNext();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
215
src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp
vendored
Normal file
215
src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp
vendored
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2021 Jonathan Poelen <jonathan.poelen@gmail.com>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KSYNTAXHIGHLIGHTING_HIGHLIGHTING_DATA_P_H
|
||||||
|
#define KSYNTAXHIGHLIGHTING_HIGHLIGHTING_DATA_P_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QXmlStreamReader;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace KSyntaxHighlighting
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Represents the raw xml data of a context and its rules.
|
||||||
|
* After resolving contexts, members of this class are no longer
|
||||||
|
* use and the instance can be freed to recover used memory.
|
||||||
|
*/
|
||||||
|
class HighlightingContextData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void load(const QString &defName, QXmlStreamReader &reader);
|
||||||
|
|
||||||
|
struct ContextSwitch {
|
||||||
|
ContextSwitch() = default;
|
||||||
|
ContextSwitch(QStringView str);
|
||||||
|
|
||||||
|
QStringView contextName() const;
|
||||||
|
QStringView defName() const;
|
||||||
|
|
||||||
|
bool isStay() const;
|
||||||
|
|
||||||
|
int popCount() const
|
||||||
|
{
|
||||||
|
return m_popCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_popCount = 0;
|
||||||
|
int m_defNameIndex = -1;
|
||||||
|
QString m_contextAndDefName;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Rule {
|
||||||
|
enum class Type : quint8 {
|
||||||
|
Unknown,
|
||||||
|
AnyChar,
|
||||||
|
Detect2Chars,
|
||||||
|
DetectChar,
|
||||||
|
HlCOct,
|
||||||
|
IncludeRules,
|
||||||
|
Int,
|
||||||
|
Keyword,
|
||||||
|
LineContinue,
|
||||||
|
RangeDetect,
|
||||||
|
RegExpr,
|
||||||
|
StringDetect,
|
||||||
|
WordDetect,
|
||||||
|
Float,
|
||||||
|
HlCStringChar,
|
||||||
|
DetectIdentifier,
|
||||||
|
DetectSpaces,
|
||||||
|
HlCChar,
|
||||||
|
HlCHex,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnyChar {
|
||||||
|
QString chars;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Detect2Chars {
|
||||||
|
QChar char1;
|
||||||
|
QChar char2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DetectChar {
|
||||||
|
QChar char1;
|
||||||
|
bool dynamic;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WordDelimiters {
|
||||||
|
QString additionalDeliminator;
|
||||||
|
QString weakDeliminator;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Float {
|
||||||
|
WordDelimiters wordDelimiters;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HlCHex {
|
||||||
|
WordDelimiters wordDelimiters;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HlCOct {
|
||||||
|
WordDelimiters wordDelimiters;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IncludeRules {
|
||||||
|
QString contextName;
|
||||||
|
bool includeAttribute;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Int {
|
||||||
|
WordDelimiters wordDelimiters;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Keyword {
|
||||||
|
QString name;
|
||||||
|
WordDelimiters wordDelimiters;
|
||||||
|
Qt::CaseSensitivity caseSensitivityOverride;
|
||||||
|
bool hasCaseSensitivityOverride;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LineContinue {
|
||||||
|
QChar char1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RangeDetect {
|
||||||
|
QChar begin;
|
||||||
|
QChar end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RegExpr {
|
||||||
|
QString pattern;
|
||||||
|
Qt::CaseSensitivity caseSensitivity;
|
||||||
|
bool isMinimal;
|
||||||
|
bool dynamic;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringDetect {
|
||||||
|
QString string;
|
||||||
|
Qt::CaseSensitivity caseSensitivity;
|
||||||
|
bool dynamic;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WordDetect {
|
||||||
|
QString word;
|
||||||
|
WordDelimiters wordDelimiters;
|
||||||
|
Qt::CaseSensitivity caseSensitivity;
|
||||||
|
};
|
||||||
|
|
||||||
|
union Data {
|
||||||
|
AnyChar anyChar;
|
||||||
|
Detect2Chars detect2Chars;
|
||||||
|
DetectChar detectChar;
|
||||||
|
HlCOct hlCOct;
|
||||||
|
IncludeRules includeRules;
|
||||||
|
Int detectInt;
|
||||||
|
Keyword keyword;
|
||||||
|
LineContinue lineContinue;
|
||||||
|
RangeDetect rangeDetect;
|
||||||
|
RegExpr regExpr;
|
||||||
|
StringDetect stringDetect;
|
||||||
|
WordDetect wordDetect;
|
||||||
|
Float detectFloat;
|
||||||
|
HlCHex hlCHex;
|
||||||
|
|
||||||
|
Data() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Data()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Common {
|
||||||
|
QString contextName;
|
||||||
|
QString attributeName;
|
||||||
|
QString beginRegionName;
|
||||||
|
QString endRegionName;
|
||||||
|
int column = -1;
|
||||||
|
bool firstNonSpace = false;
|
||||||
|
bool lookAhead = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type = Type::Unknown;
|
||||||
|
Common common;
|
||||||
|
Data data;
|
||||||
|
|
||||||
|
Rule() noexcept;
|
||||||
|
Rule(Rule &&other) noexcept;
|
||||||
|
Rule(const Rule &other);
|
||||||
|
~Rule();
|
||||||
|
|
||||||
|
// since nothing is deleted in the rules vector, these functions do not need to be implemented
|
||||||
|
Rule &operator=(Rule &&other) = delete;
|
||||||
|
Rule &operator=(const Rule &other) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attribute name, to lookup our format
|
||||||
|
*/
|
||||||
|
QString attribute;
|
||||||
|
|
||||||
|
QString lineEndContext;
|
||||||
|
QString lineEmptyContext;
|
||||||
|
QString fallthroughContext;
|
||||||
|
|
||||||
|
std::vector<Rule> rules;
|
||||||
|
|
||||||
|
bool noIndentationBasedFolding = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -44,6 +44,11 @@ public:
|
|||||||
return m_keywords;
|
return m_keywords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Qt::CaseSensitivity caseSensitivity() const
|
||||||
|
{
|
||||||
|
return m_caseSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
void setKeywordList(const QStringList &keywords)
|
void setKeywordList(const QStringList &keywords)
|
||||||
{
|
{
|
||||||
m_keywords = keywords;
|
m_keywords = keywords;
|
||||||
@@ -53,7 +58,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Checks if @p str is a keyword in this list. */
|
/** Checks if @p str is a keyword in this list. */
|
||||||
bool contains(QStringView str) const { return contains(str, m_caseSensitive); }
|
bool contains(QStringView str) const
|
||||||
|
{
|
||||||
|
return contains(str, m_caseSensitive);
|
||||||
|
}
|
||||||
|
|
||||||
/** Checks if @p str is a keyword in this list, overriding the global case-sensitivity setting. */
|
/** Checks if @p str is a keyword in this list, overriding the global case-sensitivity setting. */
|
||||||
bool contains(QStringView str, Qt::CaseSensitivity caseSensitive) const;
|
bool contains(QStringView str, Qt::CaseSensitivity caseSensitive) const;
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
#include "xml_p.h"
|
#include "xml_p.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QXmlStreamReader>
|
|
||||||
|
|
||||||
using namespace KSyntaxHighlighting;
|
using namespace KSyntaxHighlighting;
|
||||||
|
|
||||||
@@ -97,172 +96,137 @@ static QString replaceCaptures(const QString &pattern, const QStringList &captur
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rule::~Rule()
|
static MatchResult matchString(QStringView pattern, QStringView text, int offset, Qt::CaseSensitivity caseSensitivity)
|
||||||
{
|
{
|
||||||
if (!m_additionalDeliminator.isEmpty() || !m_weakDeliminator.isEmpty()) {
|
if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, caseSensitivity) == 0) {
|
||||||
delete m_wordDelimiters;
|
return offset + pattern.size();
|
||||||
}
|
}
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
Definition Rule::definition() const
|
static void resolveAdditionalWordDelimiters(WordDelimiters &wordDelimiters, const HighlightingContextData::Rule::WordDelimiters &delimiters)
|
||||||
{
|
{
|
||||||
return m_def.definition();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rule::setDefinition(const Definition &def)
|
|
||||||
{
|
|
||||||
m_def = def;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Rule::load(QXmlStreamReader &reader)
|
|
||||||
{
|
|
||||||
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
|
|
||||||
|
|
||||||
m_attribute = reader.attributes().value(QLatin1String("attribute")).toString();
|
|
||||||
if (reader.name() != QLatin1String("IncludeRules")) { // IncludeRules uses this with a different semantic
|
|
||||||
m_context.parse(reader.attributes().value(QLatin1String("context")));
|
|
||||||
}
|
|
||||||
m_firstNonSpace = Xml::attrToBool(reader.attributes().value(QLatin1String("firstNonSpace")));
|
|
||||||
m_lookAhead = Xml::attrToBool(reader.attributes().value(QLatin1String("lookAhead")));
|
|
||||||
bool colOk = false;
|
|
||||||
m_column = reader.attributes().value(QLatin1String("column")).toInt(&colOk);
|
|
||||||
if (!colOk) {
|
|
||||||
m_column = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto regionName = reader.attributes().value(QLatin1String("beginRegion"));
|
|
||||||
if (!regionName.isEmpty()) {
|
|
||||||
m_beginRegion = FoldingRegion(FoldingRegion::Begin, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString()));
|
|
||||||
}
|
|
||||||
regionName = reader.attributes().value(QLatin1String("endRegion"));
|
|
||||||
if (!regionName.isEmpty()) {
|
|
||||||
m_endRegion = FoldingRegion(FoldingRegion::End, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = doLoad(reader);
|
|
||||||
|
|
||||||
if (m_lookAhead && m_context.isStay()) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// be done with this rule, skip all subelements, e.g. no longer supported sub-rules
|
|
||||||
reader.skipCurrentElement();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rule::resolveContext()
|
|
||||||
{
|
|
||||||
auto const &def = m_def.definition();
|
|
||||||
|
|
||||||
m_context.resolve(def);
|
|
||||||
|
|
||||||
// cache for DefinitionData::wordDelimiters, is accessed VERY often
|
// cache for DefinitionData::wordDelimiters, is accessed VERY often
|
||||||
m_wordDelimiters = &DefinitionData::get(def)->wordDelimiters;
|
if (!delimiters.additionalDeliminator.isEmpty() || !delimiters.weakDeliminator.isEmpty()) {
|
||||||
if (!m_additionalDeliminator.isEmpty() || !m_weakDeliminator.isEmpty()) {
|
wordDelimiters.append(QStringView(delimiters.additionalDeliminator));
|
||||||
m_wordDelimiters = new WordDelimiters(*m_wordDelimiters);
|
wordDelimiters.remove(QStringView(delimiters.weakDeliminator));
|
||||||
m_wordDelimiters->append(m_additionalDeliminator);
|
|
||||||
m_wordDelimiters->remove(m_weakDeliminator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rule::resolveAttributeFormat(Context *lookupContext)
|
Rule::~Rule() = default;
|
||||||
|
|
||||||
|
const IncludeRules *Rule::castToIncludeRules() const
|
||||||
{
|
{
|
||||||
|
if (m_type != Type::IncludeRules) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return static_cast<const IncludeRules *>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rule::resolveCommon(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName)
|
||||||
|
{
|
||||||
|
switch (ruleData.type) {
|
||||||
|
// IncludeRules uses this with a different semantic
|
||||||
|
case HighlightingContextData::Rule::Type::IncludeRules:
|
||||||
|
m_type = Type::IncludeRules;
|
||||||
|
return true;
|
||||||
|
case HighlightingContextData::Rule::Type::LineContinue:
|
||||||
|
m_type = Type::LineContinue;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_type = Type::OtherRule;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* try to get our format from the definition we stem from
|
* try to get our format from the definition we stem from
|
||||||
*/
|
*/
|
||||||
if (!m_attribute.isEmpty()) {
|
if (!ruleData.common.attributeName.isEmpty()) {
|
||||||
m_attributeFormat = DefinitionData::get(definition())->formatByName(m_attribute);
|
m_attributeFormat = def.formatByName(ruleData.common.attributeName);
|
||||||
if (!m_attributeFormat.isValid()) {
|
if (!m_attributeFormat.isValid()) {
|
||||||
qCWarning(Log) << "Rule: Unknown format" << m_attribute << "in context" << lookupContext->name() << "of definition" << definition().name();
|
qCWarning(Log) << "Rule: Unknown format" << ruleData.common.attributeName << "in context" << lookupContextName << "of definition" << def.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_firstNonSpace = ruleData.common.firstNonSpace;
|
||||||
|
m_lookAhead = ruleData.common.lookAhead;
|
||||||
|
m_column = ruleData.common.column;
|
||||||
|
|
||||||
|
if (!ruleData.common.beginRegionName.isEmpty()) {
|
||||||
|
m_beginRegion = FoldingRegion(FoldingRegion::Begin, def.foldingRegionId(ruleData.common.beginRegionName));
|
||||||
|
}
|
||||||
|
if (!ruleData.common.endRegionName.isEmpty()) {
|
||||||
|
m_endRegion = FoldingRegion(FoldingRegion::End, def.foldingRegionId(ruleData.common.endRegionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_context.resolve(def, ruleData.common.contextName);
|
||||||
|
|
||||||
|
return !(m_lookAhead && m_context.isStay());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Rule::doLoad(QXmlStreamReader &reader)
|
static Rule::Ptr createRule(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName)
|
||||||
{
|
{
|
||||||
Q_UNUSED(reader);
|
using Type = HighlightingContextData::Rule::Type;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rule::loadAdditionalWordDelimiters(QXmlStreamReader &reader)
|
switch (ruleData.type) {
|
||||||
{
|
case Type::AnyChar:
|
||||||
m_additionalDeliminator = reader.attributes().value(QLatin1String("additionalDeliminator")).toString();
|
return std::make_shared<AnyChar>(ruleData.data.anyChar);
|
||||||
m_weakDeliminator = reader.attributes().value(QLatin1String("weakDeliminator")).toString();
|
case Type::DetectChar:
|
||||||
}
|
return std::make_shared<DetectChar>(ruleData.data.detectChar);
|
||||||
|
case Type::Detect2Chars:
|
||||||
Rule::Ptr Rule::create(QStringView name)
|
return std::make_shared<Detect2Chars>(ruleData.data.detect2Chars);
|
||||||
{
|
case Type::IncludeRules:
|
||||||
if (name == QLatin1String("AnyChar")) {
|
return std::make_shared<IncludeRules>(ruleData.data.includeRules);
|
||||||
return std::make_shared<AnyChar>();
|
case Type::Int:
|
||||||
}
|
return std::make_shared<Int>(def, ruleData.data.detectInt);
|
||||||
if (name == QLatin1String("DetectChar")) {
|
case Type::Keyword:
|
||||||
return std::make_shared<DetectChar>();
|
return KeywordListRule::create(def, ruleData.data.keyword, lookupContextName);
|
||||||
}
|
case Type::LineContinue:
|
||||||
if (name == QLatin1String("Detect2Chars")) {
|
return std::make_shared<LineContinue>(ruleData.data.lineContinue);
|
||||||
return std::make_shared<Detect2Char>();
|
case Type::RangeDetect:
|
||||||
}
|
return std::make_shared<RangeDetect>(ruleData.data.rangeDetect);
|
||||||
if (name == QLatin1String("DetectIdentifier")) {
|
case Type::RegExpr:
|
||||||
return std::make_shared<DetectIdentifier>();
|
return std::make_shared<RegExpr>(ruleData.data.regExpr);
|
||||||
}
|
case Type::StringDetect:
|
||||||
if (name == QLatin1String("DetectSpaces")) {
|
if (ruleData.data.stringDetect.dynamic) {
|
||||||
return std::make_shared<DetectSpaces>();
|
return std::make_shared<DynamicStringDetect>(ruleData.data.stringDetect);
|
||||||
}
|
}
|
||||||
if (name == QLatin1String("Float")) {
|
return std::make_shared<StringDetect>(ruleData.data.stringDetect);
|
||||||
return std::make_shared<Float>();
|
case Type::WordDetect:
|
||||||
}
|
return std::make_shared<WordDetect>(def, ruleData.data.wordDetect);
|
||||||
if (name == QLatin1String("Int")) {
|
case Type::Float:
|
||||||
return std::make_shared<Int>();
|
return std::make_shared<Float>(def, ruleData.data.detectFloat);
|
||||||
}
|
case Type::HlCOct:
|
||||||
if (name == QLatin1String("HlCChar")) {
|
return std::make_shared<HlCOct>(def, ruleData.data.hlCOct);
|
||||||
return std::make_shared<HlCChar>();
|
case Type::HlCStringChar:
|
||||||
}
|
|
||||||
if (name == QLatin1String("HlCHex")) {
|
|
||||||
return std::make_shared<HlCHex>();
|
|
||||||
}
|
|
||||||
if (name == QLatin1String("HlCOct")) {
|
|
||||||
return std::make_shared<HlCOct>();
|
|
||||||
}
|
|
||||||
if (name == QLatin1String("HlCStringChar")) {
|
|
||||||
return std::make_shared<HlCStringChar>();
|
return std::make_shared<HlCStringChar>();
|
||||||
}
|
case Type::DetectIdentifier:
|
||||||
if (name == QLatin1String("IncludeRules")) {
|
return std::make_shared<DetectIdentifier>();
|
||||||
return std::make_shared<IncludeRules>();
|
case Type::DetectSpaces:
|
||||||
}
|
return std::make_shared<DetectSpaces>();
|
||||||
if (name == QLatin1String("keyword")) {
|
case Type::HlCChar:
|
||||||
return std::make_shared<KeywordListRule>();
|
return std::make_shared<HlCChar>();
|
||||||
}
|
case Type::HlCHex:
|
||||||
if (name == QLatin1String("LineContinue")) {
|
return std::make_shared<HlCHex>(def, ruleData.data.hlCHex);
|
||||||
return std::make_shared<LineContinue>();
|
|
||||||
}
|
case Type::Unknown:;
|
||||||
if (name == QLatin1String("RangeDetect")) {
|
|
||||||
return std::make_shared<RangeDetect>();
|
|
||||||
}
|
|
||||||
if (name == QLatin1String("RegExpr")) {
|
|
||||||
return std::make_shared<RegExpr>();
|
|
||||||
}
|
|
||||||
if (name == QLatin1String("StringDetect")) {
|
|
||||||
return std::make_shared<StringDetect>();
|
|
||||||
}
|
|
||||||
if (name == QLatin1String("WordDetect")) {
|
|
||||||
return std::make_shared<WordDetect>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qCWarning(Log) << "Unknown rule type:" << name;
|
return Rule::Ptr(nullptr);
|
||||||
return Ptr(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Rule::isWordDelimiter(QChar c) const
|
Rule::Ptr Rule::create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName)
|
||||||
{
|
{
|
||||||
return m_wordDelimiters->contains(c);
|
auto rule = createRule(def, ruleData, lookupContextName);
|
||||||
|
if (rule && !rule->resolveCommon(def, ruleData, lookupContextName)) {
|
||||||
|
rule.reset();
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnyChar::doLoad(QXmlStreamReader &reader)
|
AnyChar::AnyChar(const HighlightingContextData::Rule::AnyChar &data)
|
||||||
|
: m_chars(data.chars)
|
||||||
{
|
{
|
||||||
m_chars = reader.attributes().value(QLatin1String("String")).toString();
|
|
||||||
if (m_chars.size() == 1) {
|
|
||||||
qCDebug(Log) << "AnyChar rule with just one char: use DetectChar instead.";
|
|
||||||
}
|
|
||||||
return !m_chars.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
@@ -273,18 +237,11 @@ MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &)
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DetectChar::doLoad(QXmlStreamReader &reader)
|
DetectChar::DetectChar(const HighlightingContextData::Rule::DetectChar &data)
|
||||||
|
: m_char(data.char1)
|
||||||
|
, m_captureIndex(data.dynamic ? data.char1.digitValue() : 0)
|
||||||
{
|
{
|
||||||
const auto s = reader.attributes().value(QLatin1String("char"));
|
m_dynamic = data.dynamic;
|
||||||
if (s.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_char = s.at(0);
|
|
||||||
m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic")));
|
|
||||||
if (m_dynamic) {
|
|
||||||
m_captureIndex = m_char.digitValue();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const
|
MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const
|
||||||
@@ -305,19 +262,13 @@ MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Detect2Char::doLoad(QXmlStreamReader &reader)
|
Detect2Chars::Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data)
|
||||||
|
: m_char1(data.char1)
|
||||||
|
, m_char2(data.char2)
|
||||||
{
|
{
|
||||||
const auto s1 = reader.attributes().value(QLatin1String("char"));
|
|
||||||
const auto s2 = reader.attributes().value(QLatin1String("char1"));
|
|
||||||
if (s1.isEmpty() || s2.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_char1 = s1.at(0);
|
|
||||||
m_char2 = s2.at(0);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult Detect2Char::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
{
|
{
|
||||||
if (text.size() - offset < 2) {
|
if (text.size() - offset < 2) {
|
||||||
return offset;
|
return offset;
|
||||||
@@ -352,15 +303,15 @@ MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringLis
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Float::doLoad(QXmlStreamReader &reader)
|
Float::Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data)
|
||||||
|
: m_wordDelimiters(def.wordDelimiters)
|
||||||
{
|
{
|
||||||
loadAdditionalWordDelimiters(reader);
|
resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
{
|
{
|
||||||
if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
|
if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,15 +383,15 @@ MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &)
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HlCHex::doLoad(QXmlStreamReader &reader)
|
HlCHex::HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data)
|
||||||
|
: m_wordDelimiters(def.wordDelimiters)
|
||||||
{
|
{
|
||||||
loadAdditionalWordDelimiters(reader);
|
resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
{
|
{
|
||||||
if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
|
if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,15 +417,15 @@ MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) c
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HlCOct::doLoad(QXmlStreamReader &reader)
|
HlCOct::HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data)
|
||||||
|
: m_wordDelimiters(def.wordDelimiters)
|
||||||
{
|
{
|
||||||
loadAdditionalWordDelimiters(reader);
|
resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
{
|
{
|
||||||
if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
|
if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,53 +454,28 @@ MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringLi
|
|||||||
return matchEscapedChar(text, offset);
|
return matchEscapedChar(text, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString IncludeRules::contextName() const
|
IncludeRules::IncludeRules(const HighlightingContextData::Rule::IncludeRules &data)
|
||||||
|
: m_contextName(data.contextName)
|
||||||
|
, m_includeAttribute(data.includeAttribute)
|
||||||
{
|
{
|
||||||
return m_contextName;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString IncludeRules::definitionName() const
|
|
||||||
{
|
|
||||||
return m_defName;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IncludeRules::includeAttribute() const
|
|
||||||
{
|
|
||||||
return m_includeAttribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IncludeRules::doLoad(QXmlStreamReader &reader)
|
|
||||||
{
|
|
||||||
const auto s = reader.attributes().value(QLatin1String("context"));
|
|
||||||
const auto split = s.split(QString::fromLatin1("##"), Qt::KeepEmptyParts);
|
|
||||||
if (split.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_contextName = split.at(0).toString();
|
|
||||||
if (split.size() > 1) {
|
|
||||||
m_defName = split.at(1).toString();
|
|
||||||
}
|
|
||||||
m_includeAttribute = Xml::attrToBool(reader.attributes().value(QLatin1String("includeAttrib")));
|
|
||||||
|
|
||||||
return !m_contextName.isEmpty() || !m_defName.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(text);
|
Q_UNUSED(text);
|
||||||
qCWarning(Log) << "Unresolved include rule for" << m_contextName << "##" << m_defName;
|
qCWarning(Log) << "Unresolved include rule";
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Int::doLoad(QXmlStreamReader &reader)
|
Int::Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data)
|
||||||
|
: m_wordDelimiters(def.wordDelimiters)
|
||||||
{
|
{
|
||||||
loadAdditionalWordDelimiters(reader);
|
resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
{
|
{
|
||||||
if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) {
|
if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,67 +485,61 @@ MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) cons
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KeywordListRule::doLoad(QXmlStreamReader &reader)
|
Rule::Ptr KeywordListRule::create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* get our keyword list, if not found => bail out
|
* get our keyword list, if not found => bail out
|
||||||
*/
|
*/
|
||||||
auto defData = DefinitionData::get(definition());
|
auto *keywordList = def.keywordList(data.name);
|
||||||
m_keywordList = defData->keywordList(reader.attributes().value(QLatin1String("String")).toString());
|
if (!keywordList) {
|
||||||
if (!m_keywordList) {
|
qCWarning(Log) << "Rule: Unknown keyword list" << data.name << "in context" << lookupContextName << "of definition" << def.name;
|
||||||
return false;
|
return Rule::Ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keywordList->isEmpty()) {
|
||||||
|
return Rule::Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we might overwrite the case sensitivity
|
* we might overwrite the case sensitivity
|
||||||
* then we need to init the list for lookup of that sensitivity setting
|
* then we need to init the list for lookup of that sensitivity setting
|
||||||
*/
|
*/
|
||||||
if (reader.attributes().hasAttribute(QLatin1String("insensitive"))) {
|
if (data.hasCaseSensitivityOverride) {
|
||||||
m_hasCaseSensitivityOverride = true;
|
keywordList->initLookupForCaseSensitivity(data.caseSensitivityOverride);
|
||||||
m_caseSensitivityOverride = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
|
|
||||||
m_keywordList->initLookupForCaseSensitivity(m_caseSensitivityOverride);
|
|
||||||
} else {
|
|
||||||
m_hasCaseSensitivityOverride = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAdditionalWordDelimiters(reader);
|
return std::make_shared<KeywordListRule>(*keywordList, def, data);
|
||||||
|
}
|
||||||
|
|
||||||
return !m_keywordList->isEmpty();
|
KeywordListRule::KeywordListRule(const KeywordList &keywordList, DefinitionData &def, const HighlightingContextData::Rule::Keyword &data)
|
||||||
|
: m_wordDelimiters(def.wordDelimiters)
|
||||||
|
, m_keywordList(keywordList)
|
||||||
|
, m_caseSensitivity(data.hasCaseSensitivityOverride ? data.caseSensitivityOverride : keywordList.caseSensitivity())
|
||||||
|
{
|
||||||
|
resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
{
|
{
|
||||||
auto newOffset = offset;
|
auto newOffset = offset;
|
||||||
while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset))) {
|
while (text.size() > newOffset && !m_wordDelimiters.contains(text.at(newOffset))) {
|
||||||
++newOffset;
|
++newOffset;
|
||||||
}
|
}
|
||||||
if (newOffset == offset) {
|
if (newOffset == offset) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_hasCaseSensitivityOverride) {
|
if (m_keywordList.contains(text.mid(offset, newOffset - offset), m_caseSensitivity)) {
|
||||||
if (m_keywordList->contains(text.mid(offset, newOffset - offset), m_caseSensitivityOverride)) {
|
return newOffset;
|
||||||
return newOffset;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (m_keywordList->contains(text.mid(offset, newOffset - offset))) {
|
|
||||||
return newOffset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't match, but we can skip until newOffset as we can't start a keyword in-between
|
// we don't match, but we can skip until newOffset as we can't start a keyword in-between
|
||||||
return MatchResult(offset, newOffset);
|
return MatchResult(offset, newOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LineContinue::doLoad(QXmlStreamReader &reader)
|
LineContinue::LineContinue(const HighlightingContextData::Rule::LineContinue &data)
|
||||||
|
: m_char(data.char1)
|
||||||
{
|
{
|
||||||
const auto s = reader.attributes().value(QLatin1String("char"));
|
|
||||||
if (s.isEmpty()) {
|
|
||||||
m_char = QLatin1Char('\\');
|
|
||||||
} else {
|
|
||||||
m_char = s.at(0);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
@@ -630,16 +550,10 @@ MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringLis
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RangeDetect::doLoad(QXmlStreamReader &reader)
|
RangeDetect::RangeDetect(const HighlightingContextData::Rule::RangeDetect &data)
|
||||||
|
: m_begin(data.begin)
|
||||||
|
, m_end(data.end)
|
||||||
{
|
{
|
||||||
const auto s1 = reader.attributes().value(QLatin1String("char"));
|
|
||||||
const auto s2 = reader.attributes().value(QLatin1String("char1"));
|
|
||||||
if (s1.isEmpty() || s2.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_begin = s1.at(0);
|
|
||||||
m_end = s2.at(0);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
@@ -661,25 +575,20 @@ MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegExpr::doLoad(QXmlStreamReader &reader)
|
RegExpr::RegExpr(const HighlightingContextData::Rule::RegExpr &data)
|
||||||
{
|
{
|
||||||
m_regexp.setPattern(reader.attributes().value(QLatin1String("String")).toString());
|
m_regexp.setPattern(data.pattern);
|
||||||
|
m_regexp.setPatternOptions((data.isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption)
|
||||||
const auto isMinimal = Xml::attrToBool(reader.attributes().value(QLatin1String("minimal")));
|
| (data.caseSensitivity == Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption)
|
||||||
const auto isCaseInsensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive")));
|
|
||||||
m_regexp.setPatternOptions((isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption)
|
|
||||||
| (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption)
|
|
||||||
// DontCaptureOption is removed by resolvePostProcessing() when necessary
|
// DontCaptureOption is removed by resolvePostProcessing() when necessary
|
||||||
| QRegularExpression::DontCaptureOption
|
| QRegularExpression::DontCaptureOption
|
||||||
// ensure Unicode support is enabled
|
// ensure Unicode support is enabled
|
||||||
| QRegularExpression::UseUnicodePropertiesOption);
|
| QRegularExpression::UseUnicodePropertiesOption);
|
||||||
|
|
||||||
m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic")));
|
m_dynamic = data.dynamic;
|
||||||
|
|
||||||
return !m_regexp.pattern().isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSyntaxHighlighting::RegExpr::resolvePostProcessing()
|
void RegExpr::resolvePostProcessing()
|
||||||
{
|
{
|
||||||
if (m_isResolved) {
|
if (m_isResolved) {
|
||||||
return;
|
return;
|
||||||
@@ -728,11 +637,7 @@ MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &ca
|
|||||||
/**
|
/**
|
||||||
* match the pattern
|
* match the pattern
|
||||||
*/
|
*/
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
|
|
||||||
const auto result = regexp.match(text.toString(), offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
|
|
||||||
#else
|
|
||||||
const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
|
const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
|
||||||
#endif
|
|
||||||
if (result.capturedStart() == offset) {
|
if (result.capturedStart() == offset) {
|
||||||
/**
|
/**
|
||||||
* we only need to compute the captured texts if we have real capture groups
|
* we only need to compute the captured texts if we have real capture groups
|
||||||
@@ -756,33 +661,39 @@ MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &ca
|
|||||||
return MatchResult(offset, result.capturedStart());
|
return MatchResult(offset, result.capturedStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringDetect::doLoad(QXmlStreamReader &reader)
|
StringDetect::StringDetect(const HighlightingContextData::Rule::StringDetect &data)
|
||||||
|
: m_string(data.string)
|
||||||
|
, m_caseSensitivity(data.caseSensitivity)
|
||||||
{
|
{
|
||||||
m_string = reader.attributes().value(QLatin1String("String")).toString();
|
|
||||||
m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
|
|
||||||
m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic")));
|
|
||||||
return !m_string.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const
|
MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
|
{
|
||||||
|
return matchString(m_string, text, offset, m_caseSensitivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicStringDetect::DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data)
|
||||||
|
: m_string(data.string)
|
||||||
|
, m_caseSensitivity(data.caseSensitivity)
|
||||||
|
{
|
||||||
|
m_dynamic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchResult DynamicStringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* for dynamic case: create new pattern with right instantiation
|
* for dynamic case: create new pattern with right instantiation
|
||||||
*/
|
*/
|
||||||
const auto &pattern = m_dynamic ? replaceCaptures(m_string, captures, false) : m_string;
|
const auto pattern = replaceCaptures(m_string, captures, false);
|
||||||
|
return matchString(pattern, text, offset, m_caseSensitivity);
|
||||||
if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0) {
|
|
||||||
return offset + pattern.size();
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WordDetect::doLoad(QXmlStreamReader &reader)
|
WordDetect::WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data)
|
||||||
|
: m_wordDelimiters(def.wordDelimiters)
|
||||||
|
, m_word(data.word)
|
||||||
|
, m_caseSensitivity(data.caseSensitivity)
|
||||||
{
|
{
|
||||||
m_word = reader.attributes().value(QLatin1String("String")).toString();
|
resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
|
||||||
m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
|
|
||||||
loadAdditionalWordDelimiters(reader);
|
|
||||||
return !m_word.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const
|
MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const
|
||||||
@@ -795,7 +706,7 @@ MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList
|
|||||||
* detect delimiter characters on the inner and outer boundaries of the string
|
* detect delimiter characters on the inner and outer boundaries of the string
|
||||||
* NOTE: m_word isn't empty
|
* NOTE: m_word isn't empty
|
||||||
*/
|
*/
|
||||||
if (offset > 0 && !isWordDelimiter(text.at(offset - 1)) && !isWordDelimiter(text.at(offset))) {
|
if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1)) && !m_wordDelimiters.contains(text.at(offset))) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,7 +714,8 @@ MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())) || isWordDelimiter(text.at(offset + m_word.size() - 1))) {
|
if (text.size() == offset + m_word.size() || m_wordDelimiters.contains(text.at(offset + m_word.size()))
|
||||||
|
|| m_wordDelimiters.contains(text.at(offset + m_word.size() - 1))) {
|
||||||
return offset + m_word.size();
|
return offset + m_word.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,25 +9,24 @@
|
|||||||
#define KSYNTAXHIGHLIGHTING_RULE_P_H
|
#define KSYNTAXHIGHLIGHTING_RULE_P_H
|
||||||
|
|
||||||
#include "contextswitch_p.h"
|
#include "contextswitch_p.h"
|
||||||
#include "definition.h"
|
|
||||||
#include "definitionref_p.h"
|
#include "definitionref_p.h"
|
||||||
#include "foldingregion.h"
|
#include "foldingregion.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
#include "highlightingdata_p.hpp"
|
||||||
#include "keywordlist_p.h"
|
#include "keywordlist_p.h"
|
||||||
#include "matchresult_p.h"
|
#include "matchresult_p.h"
|
||||||
|
#include "worddelimiters_p.h"
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QXmlStreamReader;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace KSyntaxHighlighting
|
namespace KSyntaxHighlighting
|
||||||
{
|
{
|
||||||
class WordDelimiters;
|
class WordDelimiters;
|
||||||
|
class DefinitionData;
|
||||||
|
class IncludeRules;
|
||||||
|
|
||||||
class Rule
|
class Rule
|
||||||
{
|
{
|
||||||
@@ -37,9 +36,6 @@ public:
|
|||||||
|
|
||||||
typedef std::shared_ptr<Rule> Ptr;
|
typedef std::shared_ptr<Rule> Ptr;
|
||||||
|
|
||||||
Definition definition() const;
|
|
||||||
void setDefinition(const Definition &def);
|
|
||||||
|
|
||||||
const Format &attributeFormat() const
|
const Format &attributeFormat() const
|
||||||
{
|
{
|
||||||
return m_attributeFormat;
|
return m_attributeFormat;
|
||||||
@@ -80,51 +76,51 @@ public:
|
|||||||
return m_endRegion;
|
return m_endRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load(QXmlStreamReader &reader);
|
const IncludeRules *castToIncludeRules() const;
|
||||||
void resolveContext();
|
|
||||||
void resolveAttributeFormat(Context *lookupContext);
|
bool isLineContinue() const
|
||||||
|
{
|
||||||
|
return m_type == Type::LineContinue;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void resolvePostProcessing()
|
virtual void resolvePostProcessing()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0;
|
virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0;
|
||||||
|
|
||||||
static Rule::Ptr create(QStringView name);
|
static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName);
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual bool doLoad(QXmlStreamReader &reader);
|
|
||||||
|
|
||||||
bool isWordDelimiter(QChar c) const;
|
|
||||||
|
|
||||||
void loadAdditionalWordDelimiters(QXmlStreamReader &reader);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(Rule)
|
Q_DISABLE_COPY(Rule)
|
||||||
|
|
||||||
DefinitionRef m_def;
|
bool resolveCommon(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName);
|
||||||
QString m_attribute;
|
|
||||||
|
enum class Type : quint8 {
|
||||||
|
OtherRule,
|
||||||
|
LineContinue,
|
||||||
|
IncludeRules,
|
||||||
|
};
|
||||||
|
|
||||||
Format m_attributeFormat;
|
Format m_attributeFormat;
|
||||||
ContextSwitch m_context;
|
ContextSwitch m_context;
|
||||||
int m_column = -1;
|
int m_column = -1;
|
||||||
FoldingRegion m_beginRegion;
|
FoldingRegion m_beginRegion;
|
||||||
FoldingRegion m_endRegion;
|
FoldingRegion m_endRegion;
|
||||||
|
Type m_type;
|
||||||
bool m_firstNonSpace = false;
|
bool m_firstNonSpace = false;
|
||||||
bool m_lookAhead = false;
|
bool m_lookAhead = false;
|
||||||
|
|
||||||
// cache for DefinitionData::wordDelimiters, is accessed VERY often
|
|
||||||
WordDelimiters *m_wordDelimiters = nullptr;
|
|
||||||
|
|
||||||
QString m_additionalDeliminator;
|
|
||||||
QString m_weakDeliminator;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_dynamic = false;
|
bool m_dynamic = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AnyChar final : public Rule
|
class AnyChar final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
AnyChar(const HighlightingContextData::Rule::AnyChar &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -133,20 +129,24 @@ private:
|
|||||||
|
|
||||||
class DetectChar final : public Rule
|
class DetectChar final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
DetectChar(const HighlightingContextData::Rule::DetectChar &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QChar m_char;
|
QChar m_char;
|
||||||
int m_captureIndex = 0;
|
int m_captureIndex = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Detect2Char final : public Rule
|
class Detect2Chars final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QChar m_char1;
|
QChar m_char1;
|
||||||
@@ -167,33 +167,49 @@ protected:
|
|||||||
|
|
||||||
class Float final : public Rule
|
class Float final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WordDelimiters m_wordDelimiters;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IncludeRules final : public Rule
|
class IncludeRules final : public Rule
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QString contextName() const;
|
IncludeRules(const HighlightingContextData::Rule::IncludeRules &data);
|
||||||
QString definitionName() const;
|
|
||||||
bool includeAttribute() const;
|
const QString &contextName() const
|
||||||
|
{
|
||||||
|
return m_contextName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool includeAttribute() const
|
||||||
|
{
|
||||||
|
return m_includeAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_contextName;
|
QString m_contextName;
|
||||||
QString m_defName;
|
|
||||||
bool m_includeAttribute;
|
bool m_includeAttribute;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Int final : public Rule
|
class Int final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
|
|
||||||
|
private:
|
||||||
|
WordDelimiters m_wordDelimiters;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HlCChar final : public Rule
|
class HlCChar final : public Rule
|
||||||
@@ -204,16 +220,26 @@ protected:
|
|||||||
|
|
||||||
class HlCHex final : public Rule
|
class HlCHex final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WordDelimiters m_wordDelimiters;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HlCOct final : public Rule
|
class HlCOct final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WordDelimiters m_wordDelimiters;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HlCStringChar final : public Rule
|
class HlCStringChar final : public Rule
|
||||||
@@ -224,20 +250,26 @@ protected:
|
|||||||
|
|
||||||
class KeywordListRule final : public Rule
|
class KeywordListRule final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
KeywordListRule(const KeywordList &keywordList, DefinitionData &def, const HighlightingContextData::Rule::Keyword &data);
|
||||||
|
|
||||||
|
static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KeywordList *m_keywordList;
|
WordDelimiters m_wordDelimiters;
|
||||||
bool m_hasCaseSensitivityOverride;
|
const KeywordList &m_keywordList;
|
||||||
Qt::CaseSensitivity m_caseSensitivityOverride;
|
Qt::CaseSensitivity m_caseSensitivity;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LineContinue final : public Rule
|
class LineContinue final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
LineContinue(const HighlightingContextData::Rule::LineContinue &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -246,8 +278,10 @@ private:
|
|||||||
|
|
||||||
class RangeDetect final : public Rule
|
class RangeDetect final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
RangeDetect(const HighlightingContextData::Rule::RangeDetect &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -257,10 +291,12 @@ private:
|
|||||||
|
|
||||||
class RegExpr final : public Rule
|
class RegExpr final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
RegExpr(const HighlightingContextData::Rule::RegExpr &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
void resolvePostProcessing() override;
|
void resolvePostProcessing() override;
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRegularExpression m_regexp;
|
QRegularExpression m_regexp;
|
||||||
@@ -269,9 +305,24 @@ private:
|
|||||||
|
|
||||||
class StringDetect final : public Rule
|
class StringDetect final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
StringDetect(const HighlightingContextData::Rule::StringDetect &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
|
|
||||||
|
private:
|
||||||
|
QString m_string;
|
||||||
|
Qt::CaseSensitivity m_caseSensitivity;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DynamicStringDetect final : public Rule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_string;
|
QString m_string;
|
||||||
@@ -280,11 +331,14 @@ private:
|
|||||||
|
|
||||||
class WordDetect final : public Rule
|
class WordDetect final : public Rule
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool doLoad(QXmlStreamReader &reader) override;
|
MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
|
||||||
MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
WordDelimiters m_wordDelimiters;
|
||||||
QString m_word;
|
QString m_word;
|
||||||
Qt::CaseSensitivity m_caseSensitivity;
|
Qt::CaseSensitivity m_caseSensitivity;
|
||||||
};
|
};
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
using namespace KSyntaxHighlighting;
|
using namespace KSyntaxHighlighting;
|
||||||
|
|
||||||
#include <QChar>
|
#include <QChar>
|
||||||
#include <QStringView>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@@ -12,15 +12,14 @@ WordDelimiters::WordDelimiters()
|
|||||||
: asciiDelimiters{}
|
: asciiDelimiters{}
|
||||||
{
|
{
|
||||||
for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p) {
|
for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p) {
|
||||||
// int(*p) fix -Wchar-subscripts
|
asciiDelimiters.set(*p);
|
||||||
asciiDelimiters[int(*p)] = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WordDelimiters::contains(QChar c) const
|
bool WordDelimiters::contains(QChar c) const
|
||||||
{
|
{
|
||||||
if (c.unicode() < 128) {
|
if (c.unicode() < 128) {
|
||||||
return asciiDelimiters[c.unicode()];
|
return asciiDelimiters.test(c.unicode());
|
||||||
}
|
}
|
||||||
// perf tells contains is MUCH faster than binary search here, very short array
|
// perf tells contains is MUCH faster than binary search here, very short array
|
||||||
return notAsciiDelimiters.contains(c);
|
return notAsciiDelimiters.contains(c);
|
||||||
@@ -30,7 +29,7 @@ void WordDelimiters::append(QStringView s)
|
|||||||
{
|
{
|
||||||
for (QChar c : s) {
|
for (QChar c : s) {
|
||||||
if (c.unicode() < 128) {
|
if (c.unicode() < 128) {
|
||||||
asciiDelimiters[c.unicode()] = true;
|
asciiDelimiters.set(c.unicode());
|
||||||
} else {
|
} else {
|
||||||
notAsciiDelimiters.append(c);
|
notAsciiDelimiters.append(c);
|
||||||
}
|
}
|
||||||
@@ -41,7 +40,7 @@ void WordDelimiters::remove(QStringView s)
|
|||||||
{
|
{
|
||||||
for (QChar c : s) {
|
for (QChar c : s) {
|
||||||
if (c.unicode() < 128) {
|
if (c.unicode() < 128) {
|
||||||
asciiDelimiters[c.unicode()] = false;
|
asciiDelimiters.set(c.unicode(), false);
|
||||||
} else {
|
} else {
|
||||||
notAsciiDelimiters.remove(c);
|
notAsciiDelimiters.remove(c);
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
namespace KSyntaxHighlighting
|
namespace KSyntaxHighlighting
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +46,7 @@ private:
|
|||||||
* An array which represents ascii characters for very fast lookup.
|
* An array which represents ascii characters for very fast lookup.
|
||||||
* The character is used as an index and the value @c true indicates a word delimiter.
|
* The character is used as an index and the value @c true indicates a word delimiter.
|
||||||
*/
|
*/
|
||||||
bool asciiDelimiters[128];
|
std::bitset<128> asciiDelimiters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains characters that are not ascii and is empty for most syntax definition.
|
* Contains characters that are not ascii and is empty for most syntax definition.
|
||||||
|
Reference in New Issue
Block a user