TextEditor: replace generic highlighter with ksyntaxhighlighting

Fixes: QTCREATORBUG-21029
Change-Id: I9894c4384e0e47da6bf030b7b8e07c3ad4737ff3
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
David Schulz
2018-11-08 11:39:48 +01:00
parent 1c77d7e1a7
commit 14834e6b0a
198 changed files with 16280 additions and 9006 deletions

View File

@@ -51,6 +51,45 @@
\QC contains the following third-party components:
\list
\li \b{Syntax highlighting engine for Kate syntax definitions}
This is a stand-alone implementation of the Kate syntax highlighting engine.
It's meant as a building block for text editors as well as for simple highlighted
text rendering (e.g. as HTML), supporting both integration with a custom editor
as well as a ready-to-use QSyntaxHighlighter sub-class.
Distributed under the:
\code
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\endcode
The source code of KSyntaxHighlighting can be found
here:
\list
\li \l{https://cgit.kde.org/syntax-highlighting.git}
\li QtCreator/src/libs/3rdparty/syntax-highlighting
\li \l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/3rdparty/syntax-highlighting}
\endlist
\li \b{Reference implementation for std::experimental::optional}
Copyright (C) 2011-2012 Andrzej Krzemienski

View File

@@ -196,6 +196,7 @@ for(dir, QTC_PLUGIN_DIRS) {
QTC_LIB_DIRS_FROM_ENVIRONMENT = $$(QTC_LIB_DIRS)
QTC_LIB_DIRS += $$split(QTC_LIB_DIRS_FROM_ENVIRONMENT, $$QMAKE_DIRLIST_SEP)
QTC_LIB_DIRS += $$IDE_SOURCE_TREE/src/libs
QTC_LIB_DIRS += $$IDE_SOURCE_TREE/src/libs/3rdparty
for(dir, QTC_LIB_DIRS) {
INCLUDEPATH += $$dir
}

View File

@@ -0,0 +1,3 @@
{
"phabricator.uri" : "https://phabricator.kde.org/project/profile/152/"
}

View File

@@ -0,0 +1,9 @@
*.kdev4
*.orig
*.out
*.rej
*~
/compile.pl
CMakeLists.txt.user
callgrind.*
heaptrack.*

View File

@@ -0,0 +1 @@
// kate: space-indent on; indent-width 4; remove-trailing-spaces modified;

View File

@@ -0,0 +1,2 @@
CHECKSETS kde5
SKIP /autotests/input/

View File

@@ -0,0 +1,134 @@
cmake_minimum_required(VERSION 3.0)
set(KF5_VERSION "5.52.0")
project(KSyntaxHighlighting VERSION ${KF5_VERSION})
find_package(ECM 5.51.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
if(POLICY CMP0063)
cmake_policy(SET CMP0063 NEW)
endif()
include(FeatureSummary)
include(GenerateExportHeader)
include(ECMSetupVersion)
include(ECMGenerateHeaders)
include(ECMGeneratePriFile)
include(CMakePackageConfigHelpers)
include(ECMPoQmTools)
include(ECMQtDeclareLoggingCategory)
include(KDEInstallDirs)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(KDECMakeSettings)
include(ECMMarkNonGuiExecutable)
include(ECMAddQch)
ecm_setup_version(PROJECT
VARIABLE_PREFIX SyntaxHighlighting
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5SyntaxHighlightingConfigVersion.cmake"
)
#
# Dependencies
#
set(REQUIRED_QT_VERSION 5.8.0)
find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED COMPONENTS Core Network Test)
option(KSYNTAXHIGHLIGHTING_USE_GUI "Build components depending on Qt5Gui" ON)
if(KSYNTAXHIGHLIGHTING_USE_GUI)
find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED COMPONENTS Gui)
endif()
find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE QUIET OPTIONAL_COMPONENTS Widgets XmlPatterns)
set_package_properties(Qt5 PROPERTIES URL "http://qt-project.org/")
set_package_properties(Qt5Widgets PROPERTIES PURPOSE "Example application.")
set_package_properties(Qt5XmlPatterns PROPERTIES PURPOSE "Compile-time validation of syntax definition files.")
find_package(Perl REQUIRED)
set_package_properties(Perl PROPERTIES PURPOSE "Auto-generate PHP syntax definition files.")
#
# allow to install the "differently" licensed syntax xml files instead of putting them in a QRC and link them in
#
option(QRC_SYNTAX "Bundle the syntax definition files inside the library as resources" ON)
add_feature_info(SYNTAX_RESOURCE ${QRC_SYNTAX} "Bundle the syntax definition files inside the library as resources")
#
# allow to turn of lookup for syntax files and themes via QStandardPaths
#
option(NO_STANDARD_PATHS "Skip lookup of syntax and theme definitions in QStandardPaths locations" OFF)
add_feature_info(FEATURE_NO_STANDARD_PATHS ${NO_STANDARD_PATHS} "Skip lookup of syntax and theme definitions in QStandardPaths locations")
#
# API documentation
#
option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF)
add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)")
#
# Translations
#
if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po")
ecm_install_po_files_as_qm(po)
endif()
# tell the framework if it shall use the syntax files from the resource
if (QRC_SYNTAX)
add_definitions(-DHAS_SYNTAX_RESOURCE)
endif()
# skip standard paths?
if (NO_STANDARD_PATHS)
add_definitions(-DNO_STANDARD_PATHS)
endif()
#
# Actually build the stuff
#
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(data)
add_subdirectory(src)
if(TARGET Qt5::Gui)
add_subdirectory(examples)
endif()
#
# CMake package config file generation
#
set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KF5SyntaxHighlighting")
if (BUILD_QCH)
ecm_install_qch_export(
TARGETS KF5SyntaxHighlighting_QCH
FILE KF5SyntaxHighlightingQchTargets.cmake
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5SyntaxHighlightingQchTargets.cmake\")")
endif()
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/KF5SyntaxHighlightingConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5SyntaxHighlightingConfig.cmake"
INSTALL_DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/KF5SyntaxHighlightingConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/KF5SyntaxHighlightingConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel)
if(TARGET KF5SyntaxHighlighting)
install(EXPORT KF5SyntaxHighlightingTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
FILE KF5SyntaxHighlightingTargets.cmake
NAMESPACE KF5::)
endif()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_version.h"
DESTINATION "${KDE_INSTALL_INCLUDEDIR_KF5}"
COMPONENT Devel)
install(FILES org_kde_ksyntaxhighlighting.categories DESTINATION ${KDE_INSTALL_CONFDIR})
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

View File

@@ -0,0 +1,20 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,6 @@
@PACKAGE_INIT@
find_package(Qt5 @Qt5Core_VERSION_MAJOR@.@Qt5Core_VERSION_MINOR@ NO_MODULE REQUIRED COMPONENTS Core Gui)
include("${CMAKE_CURRENT_LIST_DIR}/KF5SyntaxHighlightingTargets.cmake")
@PACKAGE_INCLUDE_QCHTARGETS@

View File

View File

@@ -0,0 +1,32 @@
# Syntax Highlighting
Syntax highlighting engine for Kate syntax definitions
## Introduction
This is a stand-alone implementation of the Kate syntax highlighting engine.
It's meant as a building block for text editors as well as for simple highlighted
text rendering (e.g. as HTML), supporting both integration with a custom editor
as well as a ready-to-use QSyntaxHighlighter sub-class.
## Syntax Definition Files
This library uses Kate syntax definition files for the actual highlighting,
the file format is documented [here](https://docs.kde.org/stable5/en/applications/katepart/highlight.html).
More than 250 syntax definition files are included, additional ones are
picked up from the file system if present, so you can easily extend this
by application-specific syntax definitions for example.
## Out of scope
To not turn this into yet another text editor, the following things are considered
out of scope:
* code folding, beyond providing folding range information
* auto completion
* spell checking
* user interface for configuration
* management of text buffers or documents
If you need any of this, check out [KTextEditor](https://api.kde.org/frameworks/ktexteditor/html/).

View File

@@ -0,0 +1,9 @@
INCLUDEPATH *= $$PWD/src/lib
INCLUDEPATH *= $$PWD
SOURCES += \
$$PWD/src/lib/ksyntaxhighlighting_logging.cpp
HEADERS += \
$$PWD/ksyntaxhighlighting_version.h \
$$PWD/src/lib/ksyntaxhighlighting_logging.h

View File

@@ -0,0 +1,12 @@
// This file was generated by ecm_setup_version(): DO NOT EDIT!
#ifndef SyntaxHighlighting_VERSION_H
#define SyntaxHighlighting_VERSION_H
#define SyntaxHighlighting_VERSION_STRING "5.52.0"
#define SyntaxHighlighting_VERSION_MAJOR 5
#define SyntaxHighlighting_VERSION_MINOR 52
#define SyntaxHighlighting_VERSION_PATCH 0
#define SyntaxHighlighting_VERSION ((5<<16)|(52<<8)|(0))
#endif

View File

@@ -0,0 +1 @@
#include "abstracthighlighter.h"

View File

@@ -0,0 +1 @@
#include "definition.h"

View File

@@ -0,0 +1 @@
#include "foldingregion.h"

View File

@@ -0,0 +1 @@
#include "format.h"

View File

@@ -0,0 +1 @@
#include "repository.h"

View File

@@ -0,0 +1 @@
#include "state.h"

View File

@@ -0,0 +1 @@
#include "syntaxhighlighter.h"

View File

@@ -0,0 +1 @@
#include "theme.h"

View File

@@ -0,0 +1,11 @@
// This file was generated by ecm_qt_declare_logging_category(): DO NOT EDIT!
#include "ksyntaxhighlighting_logging.h"
namespace KSyntaxHighlighting {
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
Q_LOGGING_CATEGORY(Log, "org.kde.ksyntaxhighlighting", QtInfoMsg)
#else
Q_LOGGING_CATEGORY(Log, "org.kde.ksyntaxhighlighting")
#endif
}

View File

@@ -0,0 +1,11 @@
// This file was generated by ecm_qt_declare_logging_category(): DO NOT EDIT!
#ifndef ECM_QLOGGINGCATEGORY_KSYNTAXHIGHLIGHTING_LOG_KSYNTAXHIGHLIGHTING_LOGGING_H
#define ECM_QLOGGINGCATEGORY_KSYNTAXHIGHLIGHTING_LOG_KSYNTAXHIGHLIGHTING_LOGGING_H
#include <QLoggingCategory>
namespace KSyntaxHighlighting {
Q_DECLARE_LOGGING_CATEGORY(Log)
}
#endif

View File

@@ -0,0 +1,61 @@
# generate PHP definitions
macro(generate_php_syntax_definition targetFile srcFile)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/syntax)
execute_process(COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generators/generate-php.pl
INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/syntax/${srcFile}
OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/syntax/${targetFile})
endmacro()
generate_php_syntax_definition(javascript-php.xml javascript.xml)
generate_php_syntax_definition(css-php.xml css.xml)
generate_php_syntax_definition(html-php.xml html.xml)
# find all definitions
file(GLOB src_defs "${CMAKE_CURRENT_SOURCE_DIR}/syntax/*.xml")
set(defs
${src_defs}
${CMAKE_CURRENT_BINARY_DIR}/syntax/html-php.xml
${CMAKE_CURRENT_BINARY_DIR}/syntax/css-php.xml
${CMAKE_CURRENT_BINARY_DIR}/syntax/javascript-php.xml
)
# theme data resource
qt5_add_resources(themes_QRC ${CMAKE_CURRENT_SOURCE_DIR}/themes/theme-data.qrc)
# do we want syntax files bundled in the library?
if (QRC_SYNTAX)
# generate the resource file
set(qrc_file ${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc)
set(qrc_body "")
foreach(def ${defs})
get_filename_component(def_name ${def} NAME)
string(APPEND qrc_body "<file alias=\"${def_name}\">${def}</file>\n")
endforeach()
set(SYNTAX_DATA_QRC_FILES_STRING ${qrc_body})
configure_file(syntax-data.qrc.in ${qrc_file} @ONLY)
# generate the index file
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/index.katesyntax"
COMMAND katehighlightingindexer "${CMAKE_CURRENT_BINARY_DIR}/index.katesyntax" "${CMAKE_CURRENT_SOURCE_DIR}/schema/language.xsd" "${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc"
DEPENDS ${defs} ${CMAKE_CURRENT_SOURCE_DIR}/schema/language.xsd ${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc
)
# generate the qrc file manually, to make dependencies on generated files work...
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"
DEPENDS ${defs} ${CMAKE_CURRENT_BINARY_DIR}/index.katesyntax
)
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" PROPERTIES SKIP_AUTOMOC ON)
# object library to make cross-folder dependencies work, themes + syntax files
add_library(SyntaxHighlightingData OBJECT ${themes_QRC} ${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp)
else()
# install the syntax files as normal files into the prefix
install (FILES ${defs} DESTINATION share/org.kde.syntax-highlighting/syntax)
# object library to make cross-folder dependencies work, only themes
add_library(SyntaxHighlightingData OBJECT ${themes_QRC})
endif()
# set PIC to allow use in static and shared libs
set_property(TARGET SyntaxHighlightingData PROPERTY POSITION_INDEPENDENT_CODE 1)

View File

@@ -0,0 +1,11 @@
TEMPLATE = aux
include(../../../../../qtcreator.pri)
STATIC_BASE = $$PWD
STATIC_OUTPUT_BASE = $$IDE_DATA_PATH/generic-highlighter
STATIC_INSTALL_BASE = $$INSTALL_DATA_PATH/generic-highlighter
STATIC_FILES += $$files($$PWD/syntax/*, true)
include(../../../../../qtcreatordata.pri)

View File

@@ -0,0 +1,323 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "language.dtd"
[
<!ENTITY id_re "[_A-Za-z][\-_0-9A-Za-z]*">
]>
<!--
This file is part of KDE's kate project.
Copyright 2004 Alexander Neundorf (neundorf@kde.org)
Copyright 2005 Dominik Haumann (dhdev@gmx.de)
Copyright 2007,2008,2013,2014 Matthew Woehlke (mw_triad@users.sourceforge.net)
Copyright 2013-2015,2017-2018 Alex Turbov (i.zaufi@gmail.com)
**********************************************************************
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the *
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301, USA. *
**********************************************************************
-->
<language
name="CMake"
version="11"
kateversion="2.4"
section="Other"
extensions="CMakeLists.txt;*.cmake;*.cmake.in"
style="CMake"
mimetype="text/x-cmake"
author="Alex Turbov (i.zaufi@gmail.com)"
license="LGPLv2+"
>
<highlighting>
<list name="commands">
{%- for command in commands %}
<item>{{command.name}}</item>
{%- endfor %}
</list>
{% for command in commands -%}
{%- if command.named_args and command.named_args.kw %}
<list name="{{command.name}}_nargs">
{%- for arg in command.named_args.kw %}
<item>{{arg}}</item>
{%- endfor %}
</list>
{%- endif %}
{%- if command.special_args and command.special_args.kw %}
<list name="{{command.name}}_sargs">
{%- for arg in command.special_args.kw %}
<item>{{arg}}</item>
{%- endfor %}
</list>
{%- endif %}
{%- endfor %}
<list name="variables">
{%- for var in variables.kw %}
<item>{{var}}</item>
{%- endfor %}
</list>
{%- for kind in properties.kinds %}
<list name="{{ kind|replace('_', '-') }}">
{%- for prop in properties[kind].kw %}
<item>{{prop}}</item>
{%- endfor %}
</list>
{%- endfor %}
<list name="generator-expressions">
{%- for expr in generator_expressions %}
<item>{{ expr }}</item>
{%- endfor %}
</list>
<contexts>
<context attribute="Normal Text" lineEndContext="#stay" name="Normal Text">
<DetectSpaces/>
{% for command in commands -%}
<WordDetect String="{{command.name}}" insensitive="true" attribute="Command" context="{{command.name}}_ctx" />
{% endfor -%}
<RegExpr attribute="Region Marker" context="RST Documentation" String="^#\[(=*)\[\.rst:" column="0" />
<RegExpr attribute="Comment" context="Bracketed Comment" String="#\[(=*)\[" />
<DetectChar attribute="Comment" context="Comment" char="#" />
<DetectIdentifier attribute="User Function/Macro" context="User Function" />
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&id_re;@" lookAhead="true" />
<!-- Include keywords matching for language autocompleter work -->
<keyword attribute="Command" context="#stay" String="commands" />
</context>
{% for command in commands -%}
{#
<!--
{{ command|pprint }}
-->
-#}
<context attribute="Normal Text" lineEndContext="#stay" name="{{command.name}}_ctx">
<DetectChar attribute="Normal Text" context="{{command.name}}_ctx_op" char="(" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="{{command.name}}_ctx_op">
{%- if command.nested_parentheses %}
<DetectChar attribute="Normal Text" context="{{command.name}}_ctx_op_nested" char="(" />
{%- endif %}
<IncludeRules context="EndCmdPop2" />
{%- if command.named_args and command.named_args.kw %}
<keyword attribute="Named Args" context="#stay" String="{{command.name}}_nargs" />
{%- endif %}
{%- if command.special_args and command.special_args.kw %}
<keyword attribute="Special Args" context="#stay" String="{{command.name}}_sargs" />
{%- endif %}
{%- if command.property_args and command.property_args.kw %}
{%- for kind in command.property_args.kw %}
<keyword attribute="Property" context="#stay" String="{{kind}}" />
{%- if properties[kind|replace('-', '_')].re %}
<IncludeRules context="Detect More {{kind}}" />
{%- endif %}
{%- endfor %}
{%- endif %}
{%- if command is not nulary %}
<IncludeRules context="User Function Args" />
{%- if command.name == 'cmake_policy' %}
<!-- NOTE Handle CMP<NNN> as a special arg of `cmake_policy` command -->
<RegExpr attribute="Special Args" context="#stay" String="\bCMP[0-9]+\b" />
{%- endif %}
{%- endif %}
</context>
{%- if command.nested_parentheses %}
<context attribute="Normal Text" lineEndContext="#stay" name="{{command.name}}_ctx_op_nested">
<IncludeRules context="EndCmdPop" />
{%- if command.named_args and command.named_args.kw %}
<keyword attribute="Named Args" context="#stay" String="{{command.name}}_nargs" />
{%- endif %}
{%- if command.special_args and command.special_args.kw %}
<keyword attribute="Special Args" context="#stay" String="{{command.name}}_sargs" />
{%- endif %}
{%- if command.property_args and command.property_args.kw %}
{%- for kind in command.property_args.kw %}
<keyword attribute="Property" context="#stay" String="{{kind}}" />
{%- if properties[kind|replace('-', '_')].re %}
<IncludeRules context="Detect More {{kind}}" />
{%- endif %}
{%- endfor %}
{%- endif %}
<IncludeRules context="User Function Args" />
</context>
{%- endif %}
{% endfor -%}
{% for kind in properties.kinds if properties[kind].re -%}
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More {{ kind|replace('_', '-') }}">
{%- for prop in properties[kind].re %}
<RegExpr attribute="Property" context="#stay" String="{{prop}}" />
{%- endfor %}
</context>{{ '\n' }}
{% endfor -%}
<context attribute="Normal Text" lineEndContext="#stay" name="EndCmdPop">
<DetectChar attribute="Normal Text" context="#pop" char=")" />
</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">
<IncludeRules context="EndCmdPop2" />
<IncludeRules context="User Function Args" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Builtin Variables">
<keyword attribute="Builtin Variable" context="#stay" String="variables" insensitive="false" />
<IncludeRules context="Detect More Builtin Variables" />
<RegExpr attribute="Internal Name" context="#stay" String="\b_&id_re;\b" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect More Builtin Variables">
{%- for var in variables.re %}
<RegExpr attribute="Builtin Variable" context="#stay" String="{{var}}" />
{%- endfor %}
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Variable Substitutions">
<RegExpr attribute="Environment Variable Substitution" context="#stay" String="\$ENV\{\s*[\w-]+\s*\}" />
<Detect2Chars attribute="Variable Substitution" context="VarSubst" char="$" char1="{" />
<RegExpr attribute="@Variable Substitution" context="@VarSubst" String="@&id_re;@" lookAhead="true" />
</context>
<context attribute="Variable Substitution" lineEndContext="#pop" name="VarSubst">
<IncludeRules context="Detect Builtin Variables" />
<DetectIdentifier />
<DetectChar attribute="Variable Substitution" context="#pop" char="}" />
<IncludeRules context="Detect Variable Substitutions" />
</context>
<context attribute="@Variable Substitution" lineEndContext="#pop" name="@VarSubst">
<DetectChar attribute="@Variable Substitution" context="VarSubst@" char="@" />
</context>
<context attribute="@Variable Substitution" lineEndContext="#pop#pop" name="VarSubst@">
<IncludeRules context="Detect Builtin Variables" />
<DetectIdentifier />
<DetectChar attribute="@Variable Substitution" context="#pop#pop" char="@" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="User Function Args">
<Detect2Chars attribute="Normal Text" context="#stay" char="\" char1="(" />
<Detect2Chars attribute="Normal Text" context="#stay" char="\" char1=")" />
<RegExpr attribute="Escapes" context="#stay" String="\\[&quot;$n\\]" />
<DetectChar attribute="Strings" context="String" char="&quot;" />
<RegExpr attribute="Strings" context="Bracketed String" String="\[(=*)\[" />
<RegExpr attribute="Comment" context="Bracketed Comment" String="#\[(=*)\[" />
<DetectChar attribute="Comment" context="Comment" char="#" />
<IncludeRules context="Detect Builtin Variables" />
<IncludeRules context="Detect Variable Substitutions" />
<IncludeRules context="Detect Special Values" />
<IncludeRules context="Detect Aliased Targets" />
<IncludeRules context="Detect Generator Expressions" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Special Values">
<RegExpr attribute="True Special Arg" context="#stay" String="\b(TRUE|ON)\b" />
<RegExpr attribute="False Special Arg" context="#stay" String="\b(FALSE|OFF|(&id_re;-)?NOTFOUND)\b" />
<RegExpr attribute="Special Args" context="#stay" String="\bCMP[0-9][0-9][0-9]\b" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Aliased Targets">
<RegExpr attribute="Aliased Targets" context="#stay" String="\b&id_re;::&id_re;(::&id_re;)*\b" />
</context>
<context attribute="Comment" lineEndContext="#pop" name="Comment">
<LineContinue attribute="Comment" context="#pop" />
<IncludeRules context="##Alerts" />
<IncludeRules context="##Modelines" />
</context>
<context attribute="Comment" lineEndContext="#stay" name="RST Documentation" dynamic="true">
<RegExpr attribute="Region Marker" context="#pop" String="^#?\]%1\]" dynamic="true" column="0" />
<IncludeRules context="##reStructuredText" />
</context>
<context attribute="Comment" lineEndContext="#stay" name="Bracketed Comment" dynamic="true">
<RegExpr attribute="Comment" context="#pop" String=".*\]%1\]" dynamic="true" />
<IncludeRules context="##Alerts" />
<IncludeRules context="##Modelines" />
</context>
<context attribute="Strings" lineEndContext="#stay" name="String">
<RegExpr attribute="Strings" context="#pop" String="&quot;(?=[ );]|$)" />
<RegExpr attribute="Escapes" context="#stay" String="\\[&quot;$nrt\\]" />
<IncludeRules context="Detect Variable Substitutions" />
<IncludeRules context="Detect Generator Expressions" />
</context>
<context attribute="Strings" lineEndContext="#stay" name="Bracketed String" dynamic="true">
<RegExpr attribute="Strings" context="#pop" String="\]%1\]" dynamic="true" />
</context>
<context attribute="Normal Text" lineEndContext="#stay" name="Detect Generator Expressions">
<Detect2Chars attribute="Generator Expression" context="Generator Expression" char="$" char1="&lt;" />
</context>
<context attribute="Generator Expression" lineEndContext="#stay" name="Generator Expression">
<IncludeRules context="Detect Generator Expressions" />
<DetectChar attribute="Comment" context="Comment" char="#" />
<DetectChar attribute="Generator Expression" context="#pop" char="&gt;" />
<keyword attribute="Generator Expression Keyword" context="#stay" String="generator-expressions" insensitive="false" />
<IncludeRules context="Detect Aliased Targets" />
<IncludeRules context="Detect Variable Substitutions" />
</context>
</contexts>
<itemDatas>
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false" />
<itemData name="Command" defStyleNum="dsKeyword" spellChecking="false" />
<itemData name="User Function/Macro" defStyleNum="dsFunction" spellChecking="false" />
<itemData name="Property" defStyleNum="dsOthers" spellChecking="false" />
<itemData name="Aliased Targets" defStyleNum="dsBaseN" spellChecking="false" />
<itemData name="Named Args" defStyleNum="dsOthers" spellChecking="false" />
<itemData name="Special Args" defStyleNum="dsOthers" spellChecking="false" />
<itemData name="True Special Arg" defStyleNum="dsOthers" color="#30a030" selColor="#30a030" spellChecking="false" />
<itemData name="False Special Arg" defStyleNum="dsOthers" color="#e05050" selColor="#e05050" spellChecking="false" />
<itemData name="Strings" defStyleNum="dsString" spellChecking="true" />
<itemData name="Escapes" defStyleNum="dsChar" spellChecking="false" />
<itemData name="Builtin Variable" defStyleNum="dsDecVal" color="#c09050" selColor="#c09050" spellChecking="false" />
<itemData name="Variable Substitution" defStyleNum="dsDecVal" spellChecking="false" />
<itemData name="@Variable Substitution" defStyleNum="dsBaseN" spellChecking="false" />
<itemData name="Internal Name" defStyleNum="dsDecVal" color="#303030" selColor="#303030" spellChecking="false" />
<itemData name="Environment Variable Substitution" defStyleNum="dsFloat" 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="Comment" defStyleNum="dsComment" spellChecking="true" />
<itemData name="Region Marker" defStyleNum="dsRegionMarker" spellChecking="false" />
</itemDatas>
</highlighting>
<general>
<comments>
<comment name="singleLine" start="#" />
</comments>
<keywords casesensitive="1" />
</general>
</language>
<!-- kate: indent-width 2; tab-width 2; -->

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Generate Kate syntax file for CMake
#
# Copyright (c) 2017, Alex Turbov <i.zaufi@gmail.com>
#
# To install prerequisites:
#
# $ pip install --user click jinja2 yaml
#
# To use:
#
# $ ./generate-cmake-syntax.py cmake.yaml > ../syntax/cmake.xml
#
import click
import jinja2
import pathlib
import re
import yaml
import pprint
_TEMPLATED_NAME = re.compile('<[^>]+>')
_PROPERTY_KEYS = [
'global-properties'
, 'directory-properties'
, 'target-properties'
, 'source-properties'
, 'test-properties'
, 'cache-properties'
, 'install-properties'
]
_KW_RE_LIST = ['kw', 're']
def try_transform_placeholder_string_to_regex(name):
'''
NOTE Some placeholders are not IDs, but numbers...
`CMAKE_MATCH_<N>` 4 example
'''
m = _TEMPLATED_NAME.split(name)
if 'CMAKE_MATCH_' in m:
return '\\bCMAKE_MATCH_[0-9]+\\b'
return '\\b{}\\b'.format('&id_re;'.join(list(m))) if 1 < len(m) else name
def partition_iterable(fn, iterable):
true, false = [], []
for i in iterable:
(false, true)[int(fn(i))].append(i)
return true, false
def _transform_command_set(cmd, list_name):
args, args_re = partition_iterable(lambda x: _TEMPLATED_NAME.search(x) is None, cmd[list_name])
del cmd[list_name]
list_name = list_name.replace('-', '_')
cmd[list_name] = {k: sorted(set(v)) for k, v in zip(_KW_RE_LIST, [args, args_re])}
cmd[list_name]['re'] = [*map(lambda x: try_transform_placeholder_string_to_regex(x), args_re)]
return cmd
def transform_command(cmd):
can_be_nulary = True
if 'name' not in cmd:
raise RuntimeError('Command have no name')
if 'named-args' in cmd:
new_cmd = _transform_command_set(cmd, 'named-args')
assert new_cmd == cmd
can_be_nulary = False
if 'special-args' in cmd:
new_cmd = _transform_command_set(cmd, 'special-args')
assert new_cmd == cmd
can_be_nulary = False
if 'property-args' in cmd:
new_cmd = _transform_command_set(cmd, 'property-args')
assert new_cmd == cmd
can_be_nulary = False
cmd['nested_parentheses'] = cmd['nested-parentheses?'] if 'nested-parentheses?' in cmd else False
if 'nulary?' in cmd and cmd['nulary?'] and not can_be_nulary:
raise RuntimeError('Command `{}` w/ args declared nulary!?'.format(cmd['name']))
return cmd
#BEGIN Jinja filters
def cmd_is_nulary(cmd):
assert not ('named-args' in cmd or 'special-args' in cmd or 'property-args' in cmd)
return 'nulary?' in cmd and cmd['nulary?']
#END Jinja filters
@click.command()
@click.argument('input_yaml', type=click.File('r'))
@click.argument('template', type=click.File('r'), default='./cmake.xml.tpl')
def cli(input_yaml, template):
data = yaml.load(input_yaml)
# Partition `variables` list into "pure" words and regexes to match
data['variables'] = {
k: sorted(set(v)) for k, v in zip(_KW_RE_LIST, [*partition_iterable(lambda x: _TEMPLATED_NAME.search(x) is None, data['variables'])])
}
data['variables']['re'] = [*map(lambda x: try_transform_placeholder_string_to_regex(x), data['variables']['re'])]
# Transform properties and make all-properties list
data['properties'] = {}
for prop in _PROPERTY_KEYS:
python_prop_list_name = prop.replace('-', '_')
props, props_re = partition_iterable(lambda x: _TEMPLATED_NAME.search(x) is None, data[prop])
del data[prop]
data['properties'][python_prop_list_name] = {k: sorted(set(v)) for k, v in zip(_KW_RE_LIST, [props, props_re])}
data['properties'][python_prop_list_name]['re'] = [*map(lambda x: try_transform_placeholder_string_to_regex(x), props_re)]
data['properties']['kinds'] = [*map(lambda name: name.replace('-', '_'), _PROPERTY_KEYS)]
# Make all commands list
data['commands'] = [*map(lambda cmd: transform_command(cmd), data['scripting-commands'] + data['project-commands'] + data['ctest-commands'])]
data['generator_expressions'] = data['generator-expressions']
env = jinja2.Environment(
keep_trailing_newline=True
)
# Register convenience filters
env.tests['nulary'] = cmd_is_nulary
tpl = env.from_string(template.read())
result = tpl.render(data)
print(result)
if __name__ == '__main__':
cli()
# TODO Handle execptions and show errors

View File

@@ -0,0 +1,58 @@
#!/usr/bin/perl
# This perl script read stdin and write on stdout. It shall be an XML language file.
#
# * If the name of the language is 'HTML', then it creates the language 'PHP (HTML)'
# which shall be used for PHP hl.
#
# * If the name of the language is something else (say '*'), it creates the language '*/PHP'.
# This new language is the same as the old one, but is able to detect PHP everywhere.
#
# This script will correctly set extensions & mimetype, and will replace
# <IncludeRules context="##*"> by <IncludeRules context="##*/PHP">
#
# Generated languages need a language named 'PHP/PHP', which shall take care of PHP hl itself
# and which will be called every time something like <?php is encountred.
#
# Author: Jan Villat <jan.villat@net2000.ch>
# License: LGPL
my $file = "";
while (<>)
{
$file .= $_;
}
$warning = "\n\n<!-- ***** THIS FILE WAS GENERATED BY A SCRIPT - DO NOT EDIT ***** -->\n";
$file =~ s/(?=<language)/$warning\n\n\n/;
if ($file =~ /<language[^>]+name="HTML"/)
{
$root = 1;
}
if ($root == 1)
{
$file =~ s/<language([^>]+)name="[^"]*"/<language$1name="PHP (HTML)"/s;
$file =~ s/<language([^>]+)section="[^"]*"/<language$1section="Scripts"/s;
$file =~ s/<language([^>]+)extensions="[^"]*"/<language$1extensions="*.php;*.php3;*.wml;*.phtml;*.phtm;*.inc;*.ctp"/s;
$file =~ s/<language([^>]+)mimetype="[^"]*"/<language$1mimetype="text\/x-php4-src;text\/x-php3-src;text\/vnd.wap.wml;application\/x-php"/s;
}
else
{
$file =~ s/<language([^>]+)name="([^"]*)"/<language$1name="$2\/PHP" hidden="true"/s;
$file =~ s/<language([^>]+)section="[^"]*"/<language$1section="Other"/s;
$file =~ s/<language([^>]+)extensions="[^"]*"/<language$1extensions=""/s;
$file =~ s/<language([^>]+)mimetype="[^"]*"/<language$1mimetype=""/s;
}
$findphp = "<context name=\"FindPHP\" attribute=\"Normal Text\" lineEndContext=\"#stay\">\n<RegExpr context=\"##PHP/PHP\" String=\"&lt;\\?(?:=|php)?\" lookAhead=\"true\" />\n</context>\n";
$file =~ s/<IncludeRules\s([^>]*)context="([^"#]*)##(?!Alerts|Doxygen|Modelines)([^"]+)"/<IncludeRules $1context="$2##$3\/PHP"/g;
$file =~ s/(<context\s[^>]*>)/$1\n<IncludeRules context="FindPHP" \/>/g;
$file =~ s/(?=<\/contexts\s*>)/$findphp/;
print $file;
print $warning;

View File

@@ -0,0 +1,40 @@
#!/bin/bash
#
# Copyright (c) 2012-2013 by Alex Turbov
#
# Grab a documented (officially) class list from Qt project web site:
# http://qt-project.org/doc/qt-${version}/classes.html
#
version=$1
shift
case "$version" in
5*)
url="http://qt-project.org/doc/qt-${version}/qtdoc/classes.html"
;;
4*)
url="http://qt-project.org/doc/qt-${version}/classes.html"
;;
*)
echo "*** Error: Only Qt4 and Qt5 supported!"
esac
if [ -n "$version" ]; then
tmp=`mktemp`
wget -O $tmp "$url"
cat $tmp | egrep '^<dd><a href=".*\.html">.*</a></dd>$' \
| sed -e 's,<dd><a href=".*\.html">\(.*\)</a></dd>,<item> \1 </item>,' \
| grep -v 'qoutputrange'
rm $tmp
else
cat <<EOF
Usage:
$0 Qt-version
Note: Only major and minor version required
Example:
$0 4.8
EOF
fi

View File

@@ -0,0 +1,33 @@
#!/bin/bash
#
# Copyright (c) 2011-2012 by Alex Turbov
#
# Simplest (and stupid) way to get #defines from a header file(s)
#
# TODO Think about to use clang to get (an actual) list of free functions and/or types, classes, etc
# Using python bindings it seems possible and not so hard to code...
#
basepath=$1
shift
if [ -n "$*" ]; then
for f in $*; do
egrep '^\s*#\s*define\s+(Q|QT|QT3)_' ${basepath}/$f
done \
| sed 's,^\s*#\s*define\s\+\(Q[A-Z0-9_]\+\).*,<item> \1 </item>,' \
| sort \
| uniq \
| grep -v EXPORT \
| grep -v QT_BEGIN_ \
| grep -v QT_END_ \
| grep -v QT_MANGLE_
else
cat <<EOF
Usage:
$0 basepath [qt-header-filenames]
Example:
$0 /usr/include/qt4/Qt qglobal.h qconfig.h qfeatures.h
EOF
fi

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python
from __future__ import print_function
tokens = []
with open("makensiscmdhelp.output") as f: # output from `makensis /cmdhelp`
for line in f:
if line.startswith(" "):
continue # line continuation
tokens.append(line.split()[0])
keywords = [x[1:] for x in tokens if x.startswith("!")]
basefuncs = [x for x in tokens if not x.startswith("!")]
print("KEYWORDS")
for keyword in keywords:
print("<item> %s </item>" % keyword)
print()
print("BASEFUNCS")
for basefunc in basefuncs:
print("<item> %s </item>" % basefunc)

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python
# Copyright (C) 2016 Kevin Funk <kfunk@kde.org>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU Library General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This script will print XML-like code you can put into the qmake.xml
# syntax definition file
#
# Prerequisite: You need to have a qtbase checkout somewhere
#
# Usage: qmake-gen.py /path/to/qtbase/
from __future__ import print_function
import subprocess
import os
import sys
qt5Source = sys.argv[1]
qmakeKeywords = subprocess.check_output("ag --nofilename 'QMAKE_[A-Z_0-9]+' {0}/mkspecs -o".format(qt5Source), shell=True).split(os.linesep)
extraKeywords = subprocess.check_output("sed -nr 's/\\\section1 ([A-Z_0-9]{{2,100}}).*/\\1/p' {0}/qmake/doc/src/qmake-manual.qdoc".format(qt5Source), shell=True).split(os.linesep)
keywords = []
keywords = [x.strip() for x in qmakeKeywords]
keywords += [x.strip() for x in extraKeywords]
keywords = list(set(keywords)) # remove duplicates
keywords.sort()
functions = subprocess.check_output("sed -nr 's/\{{ \\\"(.+)\\\", T_.+/\\1/p' {0}/qmake/library/qmakebuiltins.cpp".format(qt5Source), shell=True).split(os.linesep)
functions.sort()
def printItems(container):
for item in container:
trimmedText = item.strip()
if not trimmedText:
continue
print("<item> %s </item>" % trimmedText)
print()
print("KEYWORDS")
printItems(keywords)
print("FUNCTIONS")
printItems(functions)

View File

@@ -0,0 +1,668 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2001 Joseph Wenninger <jowenn@kde.org>
modified (c) 2002 Anders Lund <anders@alweb.dk>
modified (c) 2003 Simon Huerlimann <simon.huerlimann@access.unizh.ch>
modified (c) 2005 Dominik Haumann <dhdev@gmx.de>
modified (c) 2008 Wilbert Berendsen <info@wilbertberendsen.nl>
This file describes the XML format used for syntax highlight descriptions
for the Kate text editor (http://kate.kde.org), which is part of the KDE
desktop environment (http://www.kde.org).
You'll find the "Writing a Kate Highlighting XML File HOWTO" at
http://kate.kde.org/doc/hlhowto.php
This format is identified using the SYSTEM identifier
SYSTEM "language.dtd"
Files using this format should include a DOCTYPE declaration like this:
<!DOCTYPE language SYSTEM "language.dtd">
You can validate your syntax files using "validatehl.sh yourSyntax.xml".
This needs xmllint from the libxml2 XML library.
In any case, the katehighlightingindexer will validate all files bundled
with KTextEditor during compile time and fail on errors.
To use your syntax file, copy it to ~/.local/share/katepart5/syntax/ in
your home directory. You have to open a new instance of kwrite/kate to use
the new syntax file.
TODO
- find a more readable way for the - -dtdvalid stuff, it's just annoying
xml comments don't allow it.
-->
<!--
Entity declarations
You can use '&per;' instead of '.'. This seems to be useful in <item> elements.
TODO
- Are there any more such pre-defined entities?
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<!--
Default Styles
Allowed predefined default styles for itemData, available are:
- dsNormal, used for normal text
- dsKeyword, used for keywords
- dsFunction, used for function calls
- dsVariable, used for variables
- dsControlFlow, used for control flow, e.g. if, then, else, continue, break
- dsOperator, used for operators such as +, -, *, ::
- dsBuiltIn, used for built-in language classes and functions
- dsExtension,used for extensions, such as boost, Qt
- dsPreprocessor, used for preprocessor statements
- dsAttribute,used for attributes, e.g. @override in java
- dsChar, used for a character
- dsSpecialChar, used for escaped characters
- dsString, used for strings
- dsVerbatimString, used for strings such as HERE docs
- dsSpecialString, used for strings such as regular expressions or LaTeX math mode
- dsImport, used for includes, imports and modules
- dsDataType, used for data types
- dsDecVal, used for decimal values
- dsBaseN, used for values with a base other than 10
- dsFloat, used for float values
- dsConstant, used for language constants
- dsComment, used for comments
- dsDocumentation, used for comments that are API documentation
- dsAnnotation, used for annotation in comments, e.g. @param in doxygen
- dsCommentVar, used for variables in comments, e.g. after @param in doxygen
- dsRegionMarker, used for region markers
- dsInformation, used for information in comments, e.g. @note in doxygen
- dsWarning, used for warnings in comments, e.g. @warning in doxygen
- dsAlert, used for warning messages such as TODO, WARNING in comments
- dsOthers, used for 'other' things
- dsError, used for error highlighting.
-->
<xs:simpleType name="defStyles">
<xs:restriction base="xs:token">
<xs:enumeration value="dsNormal"/>
<xs:enumeration value="dsKeyword"/>
<xs:enumeration value="dsFunction"/>
<xs:enumeration value="dsVariable"/>
<xs:enumeration value="dsControlFlow"/>
<xs:enumeration value="dsOperator"/>
<xs:enumeration value="dsBuiltIn"/>
<xs:enumeration value="dsExtension"/>
<xs:enumeration value="dsPreprocessor"/>
<xs:enumeration value="dsAttribute"/>
<xs:enumeration value="dsChar"/>
<xs:enumeration value="dsSpecialChar"/>
<xs:enumeration value="dsString"/>
<xs:enumeration value="dsVerbatimString"/>
<xs:enumeration value="dsSpecialString"/>
<xs:enumeration value="dsImport"/>
<xs:enumeration value="dsDataType"/>
<xs:enumeration value="dsDecVal"/>
<xs:enumeration value="dsBaseN"/>
<xs:enumeration value="dsFloat"/>
<xs:enumeration value="dsConstant"/>
<xs:enumeration value="dsComment"/>
<xs:enumeration value="dsDocumentation"/>
<xs:enumeration value="dsAnnotation"/>
<xs:enumeration value="dsCommentVar"/>
<xs:enumeration value="dsRegionMarker"/>
<xs:enumeration value="dsInformation"/>
<xs:enumeration value="dsWarning"/>
<xs:enumeration value="dsAlert"/>
<xs:enumeration value="dsOthers"/>
<xs:enumeration value="dsError"/>
</xs:restriction>
</xs:simpleType>
<!--
Language specification
name: The name of this syntax description. Used in the Highlightning Mode menu
section: The logical group to which this syntax description belongs. Used for sub menus
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]
mimetype: A list of mimetypes to decide for which documents to use this syntax description [optional]
version: Version number of this syntax description [optional]
kateversion: Kate version required for using this file [optional]
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]
author: Name of author of this hl file [optional]
license: License for this hl file [optional]
indenter: Name of the Indenter to use for this highlighting mode per default, like "cstyle" [optional]
hidden: Should it be hidden in menu [boolean, optional, default=false]
TODO
- Which matches are affected by casesensitive? keyword, RegExpr, StringDetect, WordDetect...?
WARNING: due to helper scripts, the language opening tag must be on a
*single line* and *cannot* be split in multiple lines.
-->
<xs:element name="language">
<xs:complexType>
<xs:sequence>
<xs:element ref="highlighting"/>
<xs:element minOccurs="0" ref="general"/>
<xs:element minOccurs="0" ref="spellchecking"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
<xs:attribute name="section" use="required" type="xs:NMTOKEN"/>
<xs:attribute name="extensions" use="required"/>
<xs:attribute name="version" use="required" type="xs:integer"/>
<xs:attribute name="kateversion" use="required" type="xs:decimal"/>
<xs:attribute name="style"/>
<xs:attribute name="mimetype"/>
<xs:attribute name="casesensitive" type="xs:boolean"/>
<xs:attribute name="priority" type="xs:integer"/>
<xs:attribute name="author"/>
<xs:attribute name="license"/>
<xs:attribute name="indenter"/>
<xs:attribute name="hidden" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- General options -->
<xs:element name="general">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="folding"/>
<xs:element ref="comments"/>
<xs:element ref="keywords"/>
<xs:element ref="emptyLines"/>
</xs:choice>
</xs:complexType>
</xs:element>
<!--
List of folding
indentationsensitive: If true, the code folding is indentation based.
-->
<xs:element name="folding">
<xs:complexType>
<xs:attribute name="indentationsensitive" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- List of comments -->
<xs:element name="comments">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="comment"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--
Comment specification
name: Type of this comment. Allowed are 'singleLine' and 'multiLine'
start: The comment starts with this string
end: The comment ends with this string [optional]
region: The region name of the foldable multiline comment. If you have
beginRegion="Comment" ... endRegion="Comment" you should use
region="Comment". This way uncomment works even if you do not
select all the text of the multiline comment.
position: only availalbe for type singleLine. Default is column0, to insert
the single line comment characters after the whitespaces
(= before the first non space) set position to "afterwhitespace"
-->
<xs:element name="comment">
<xs:complexType>
<xs:attribute name="name" use="required">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="singleLine"/>
<xs:enumeration value="multiLine"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="start" use="required"/>
<xs:attribute name="end"/>
<xs:attribute name="region"/>
<xs:attribute name="position">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="afterwhitespace"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<!--
Keyword options
casesensitive: Whether keywords are matched case sensitive. [boolean, optional, default=true]
weakDeliminator: Add weak deliminators [optional, default: ""]
additionalDeliminator: Add deliminators [optional]
wordWrapDeliminator: characters that are used to wrap long lines [optional]
-->
<xs:element name="keywords">
<xs:complexType>
<xs:attribute name="casesensitive" type="xs:boolean"/>
<xs:attribute name="weakDeliminator"/>
<xs:attribute name="additionalDeliminator"/>
<xs:attribute name="wordWrapDeliminator"/>
</xs:complexType>
</xs:element>
<!--
Treat lines that match a given regular expression as empty line. This is
needed for example in Python for comments (#...), as then the indentation
based folding should ignore the line.
This is only implemented for indentation based folding. If the folding
is not indentation based, the emptyLines are not used.
-->
<xs:element name="emptyLines">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="emptyLine"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--
One empty line regular expression.
regexpr: The regular expression, example from python: ^\s*#.*$
casesensitive: Sets, whether the regular expression match is performed case sesitive
-->
<xs:element name="emptyLine">
<xs:complexType>
<xs:attribute name="regexpr" use="required"/>
<xs:attribute name="casesensitive" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- Highlighting specification -->
<xs:element name="highlighting">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="list"/>
<xs:element ref="contexts"/>
<xs:element ref="itemDatas"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--
List of items
name: Name of this list
-->
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="item"/>
</xs:sequence>
<xs:attribute name="name" use="required"/>
</xs:complexType>
</xs:element>
<!--
List item
contains string used in <keyword>
-->
<xs:element name="item" type="xs:string"/>
<!-- List of contexts -->
<xs:element name="contexts">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="context"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--
context specification
name: The name of this context specification. Used in '*Context' attributes [optional]
attribute: The name of the ItemData to be used for matching text
lineEndContext: Next context if end of line is encountered
lineEmptyContext: Next context if an empty line is encountered [optional]
fallthrough: Use a fallthrough context [optional]
fallthroughContext: Fall through to this context [optional]
dynamic: Dynamic context [boolean, optional]
noIndentationBasedFolding: Python uses indentation based folding. However, Python has parts where
it does not use indentation based folding (e.g. for """ strings). In this case
switch to an own context and set this attribute to true. Then the indentation
based folding will ignore this parts and not change folding markers. [optional]
TODO:
- Explain fallthrough.
- Do we need fallthrough at all? It could be true, if fallthroughContext is set, false otherwise.
- Make lineEndContext optional, defaults to '#stay'. Reasonable?
-->
<xs:element name="context">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="keyword"/>
<xs:element ref="Float"/>
<xs:element ref="HlCOct"/>
<xs:element ref="HlCHex"/>
<xs:element ref="HlCFloat"/>
<xs:element ref="Int"/>
<xs:element ref="DetectChar"/>
<xs:element ref="Detect2Chars"/>
<xs:element ref="AnyChar"/>
<xs:element ref="StringDetect"/>
<xs:element ref="WordDetect"/>
<xs:element ref="RegExpr"/>
<xs:element ref="LineContinue"/>
<xs:element ref="HlCStringChar"/>
<xs:element ref="RangeDetect"/>
<xs:element ref="HlCChar"/>
<xs:element ref="IncludeRules"/>
<xs:element ref="DetectSpaces"/>
<xs:element ref="DetectIdentifier"/>
</xs:choice>
<xs:attribute name="name"/>
<xs:attribute name="attribute" use="required"/>
<xs:attribute name="lineEndContext" use="required"/>
<xs:attribute name="lineEmptyContext"/>
<xs:attribute name="fallthrough" type="xs:boolean"/>
<xs:attribute name="fallthroughContext"/>
<xs:attribute name="dynamic" type="xs:boolean"/>
<xs:attribute name="noIndentationBasedFolding" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!--
Common attributes
attribute: The name of the ItemData to be used for matching text
context: The name of the context to go to when this rule matches
beginRegion: Begin a region of type beginRegion [optional]
endRegion: End a region of type endRegion [optional]
firstNonSpace: should this rule only match at first non-space char in line?
column: should this rule only match at given column in line (column == count of chars in front)
-->
<xs:attributeGroup name="commonAttributes">
<xs:attribute name="attribute"/>
<xs:attribute name="context"/>
<xs:attribute name="beginRegion"/>
<xs:attribute name="endRegion"/>
<xs:attribute name="lookAhead" type="xs:boolean"/>
<xs:attribute name="firstNonSpace" type="xs:boolean"/>
<xs:attribute name="column" type="xs:integer"/>
</xs:attributeGroup>
<!--
Detect members of a keyword list
commonAttributes: Common attributes
insensitive: Is this list case-insensitive? [boolean, optional, see note]
String: Name of the list
weakDelimiter: Use weak deliminator
By default, case sensitivity is determined from <keywords casesensitive> in
<general> (default=true), but can be overridden per-list with 'insensitive'.
TODO:
- Should be weakDeliminator
- Explain deliminator
- Doesn't seem to be supported in highligh.cpp
-->
<xs:element name="keyword">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="insensitive" type="xs:boolean"/>
<xs:attribute name="String" use="required"/>
<xs:attribute name="weakDelimiter"/>
</xs:complexType>
</xs:element>
<!--
Detect a floating point number
commonAttributes: Common attributes
-->
<xs:element name="Float">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!--
Detect an octal number
commonAttributes: Common attributes
-->
<xs:element name="HlCOct">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!--
Detect a hexadecimal number
commonAttributes: Common attributes
-->
<xs:element name="HlCHex">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!--
Detect a C-style floating point number
commonAttributes: Common attributes
-->
<xs:element name="HlCFloat">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!--
Detect C-style character
commonAttributes: Common attributes
TODO
- Did I get this right?
-->
<xs:element name="HlCChar">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!--
Detect an integer number
commonAttributes: Common attributes
-->
<xs:element name="Int">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!--
Detect a single character
commonAttributes: Common attributes
char: The character to look for
dynamic: Uses 1 .. 9 as placeholders for dynamic arguments (in fact, first char of arg...) [boolean, optional, default=false]
-->
<xs:element name="DetectChar">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="char" use="required"/>
<xs:attribute name="dynamic" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!--
Detect two characters
commonAttributes: Common attributes
char: The first character
char1: The second character
-->
<xs:element name="Detect2Chars">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="char" use="required"/>
<xs:attribute name="char1" use="required"/>
</xs:complexType>
</xs:element>
<!--
Detect any group of characters
commonAttributes: Common attributes
String: A string representing the characters to look for
TODO
- Description is not descriptive enough, I'm not sure what it exactly does:-(
-->
<xs:element name="AnyChar">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="String" use="required"/>
</xs:complexType>
</xs:element>
<!--
Detect a string
commonAttributes: Common attributes
String: The string to look for
insensitive: Whether the string is matched case INsensitive. [boolean, optional, default=false]
dynamic: Uses %1 .. %9 as placeholders for dynamic arguments [boolean, optional, default=false]
TODO
- What's default of insensitive? I'm not sure...
-->
<xs:element name="StringDetect">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="String" use="required"/>
<xs:attribute name="insensitive" type="xs:boolean"/>
<xs:attribute name="dynamic" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!--
Detect a word, i.e. a string at word boundaries
commonAttributes: Common attributes
String: The string to look for
insensitive: Whether the string is matched case INsensitive. [boolean, optional, default=false]
TODO
- What's default of insensitive? I'm not sure...
-->
<xs:element name="WordDetect">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="String" use="required"/>
<xs:attribute name="insensitive" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!--
Detect a match of a regular expression
commonAttributes: Common attributes
String: The regular expression pattern
insensitive: Whether the text is matched case INsensitive. [boolean, optional, default=false]
minimal: Wheather to use minimal matching for wild cards in the pattern [boolean, optional, default='false']
dynamic: Uses %1 .. %9 as placeholders for dynamic arguments [boolean, optional, default=false]
-->
<xs:element name="RegExpr">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="String" use="required"/>
<xs:attribute name="insensitive" type="xs:boolean"/>
<xs:attribute name="minimal" type="xs:boolean"/>
<xs:attribute name="dynamic" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!--
Detect a line continuation
commonAttributes: Common attributes
char: The char marking the end of line [char, optional, default='\\']
-->
<xs:element name="LineContinue">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="char"/>
</xs:complexType>
</xs:element>
<!--
Detect a C-style escaped character
commonAttributes: Common attributes
TODO:
- Did I get this right? Only one character, or a string?
-->
<xs:element name="HlCStringChar">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!--
Detect a range of characters
commonAttributes: Common attributes
char: The character starting the range
char1: The character terminating the range
-->
<xs:element name="RangeDetect">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
<xs:attribute name="char" use="required"/>
<xs:attribute name="char1" use="required"/>
</xs:complexType>
</xs:element>
<!--
Include Rules of another context
context: The name of the context to include
includeAttrib: If this is true, the host context of the IncludeRules
will be given the attribute of the source context
-->
<xs:element name="IncludeRules">
<xs:complexType>
<xs:attribute name="context" use="required"/>
<xs:attribute name="includeAttrib" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- Detect all following Spaces -->
<xs:element name="DetectSpaces">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!-- Detect an Identifier ( == LETTER(LETTER|NUMBER|_)*) -->
<xs:element name="DetectIdentifier">
<xs:complexType>
<xs:attributeGroup ref="commonAttributes"/>
</xs:complexType>
</xs:element>
<!-- List of attributes -->
<xs:element name="itemDatas">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="itemData"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--
Attribute specification
name CDATA #REQUIRED The name of this attribute
defStyleNum CDATA #REQUIRED The index of the default style to use
color CDATA #IMPLIED Color for this style, either a hex triplet, a name or some other format recognized by Qt [optional]
selColor CDATA #IMPLIED The color for this style when text is selected [optional]
italic CDATA #IMPLIED Whether this attribute should be rendered using an italic typeface [optional, boolean, default=false]
bold CDATA #IMPLIED Whether this attribute should be renederd using a bold typeface [optional, boolean, default=false]
underline CDATA #IMPLIED Whether this attribute should be underlined [optional, boolean, default=false]
strikeOut CDATA #IMPLIED Whether this attribute should be striked out [optional, boolean, default=false]
backgroundColor CDATA #IMPLIED The background color for this style [optional]
selBackgroundColor CDATA #IMPLIED The background color for this style when text is selected [optional]
spellChecking CDATA #IMPLIED Whether this attribute should be spell checked [optional, boolean, default=true]
-->
<xs:element name="itemData">
<xs:complexType>
<xs:attribute name="name" use="required"/>
<xs:attribute name="defStyleNum" use="required" type="defStyles"/>
<xs:attribute name="color"/>
<xs:attribute name="selColor"/>
<xs:attribute name="italic" type="xs:boolean"/>
<xs:attribute name="bold" type="xs:boolean"/>
<xs:attribute name="underline" type="xs:boolean"/>
<xs:attribute name="strikeOut" type="xs:boolean"/>
<xs:attribute name="backgroundColor"/>
<xs:attribute name="selBackgroundColor"/>
<xs:attribute name="spellChecking" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<!-- Spellchecking specification -->
<xs:element name="spellchecking">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="encodings"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- List of character encodings -->
<xs:element name="encodings">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="encoding"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--
Encoding specification
sequence CDATA #REQUIRED Character sequence of the encoding; must not contain new-line characters, i.e. \n or \r
character CDATA #IMPLIED Encoded character; must be of length 1
ignored (%boolean;) #IMPLIED If true, then the encoding sequence is ignored for spellchecking
-->
<xs:element name="encoding">
<xs:complexType>
<xs:attribute name="string" use="required"/>
<xs:attribute name="char"/>
<xs:attribute name="ignored" type="xs:boolean"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,2 @@
#!/bin/sh
xmllint --noout --schema language.xsd $@

View File

@@ -0,0 +1,7 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/org.kde.syntax-highlighting/syntax">
<file alias="index.katesyntax">@CMAKE_CURRENT_BINARY_DIR@/index.katesyntax</file>
@SYNTAX_DATA_QRC_FILES_STRING@
</qresource>
</RCC>

View File

@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Kate syntax highlight filter for Markdown/MultiMarkdown documents.
Copyright 2008 Darrin Yeager. http://www.dyeager.org/
Dual-Licensed under both GPL and BSD licenses.
Extended 2009 Claes Holmerson. http://github.com/claes/kate-markdown/
-->
<!--
The [^\s]{1} is in the regex to avoid interfering with bullet list which
starts "* item". Thus emphasis/strong MUST be formed like *words here*
with the asterisks next to the beginning of the first word.
Match space or newline, followed by "*", followed by one non-space,
followed by anything non-asterisk, followed by "*", followed by
space, end-of-sentence punctuation, or the end of the line.
-->
<!DOCTYPE language SYSTEM "language.dtd"
[
<!ENTITY strongemphasisregex "(\s|^)[\*_]{3}[^\*_]+[\*_]{3}(\s|\.|,|;|:|\-|\?|$)">
<!ENTITY strongregex "(\s|^)[\*_]{2}[^\s]{1}[^\*_]+[\*_]{2}(\s|\.|,|;|:|\-|\?|$)">
<!ENTITY emphasisregex "(\s|^)[\*_]{1}[^\s]{1}[^\*_]+[\*_]{1}(\s|\.|,|;|:|\-|\?|$)">
<!ENTITY reflinkregex '\[[^\]\^]+\]\s*\[[^\]]*\]\s*(\s+\"[^\"]*\"){0,1}'>
<!ENTITY reflinktargetregex '\[[^\]\^]+\]\:\s+[^\s]+(\s+\"[^\"]*\"){0,1}'>
<!ENTITY footnoteregex "\[\^[^\]]+\]">
<!ENTITY inlinelinkregex "\[[^\]\^]+\]\s*\([^\(]*\)">
<!ENTITY inlineimageregex "\!\[[^\]\^]+\]\([^\(]*\)">
<!ENTITY refimageregex "\!\[[^\]\^]+\]\[[^\[]*\]">
<!ENTITY autolinkregex '&lt;(https?|ftp):[^\"&gt;\s]+&gt;'>
<!ENTITY mailtolinkregex "&lt;(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)&gt;">
<!ENTITY rulerregex "\s*([\*\-_]\s?){3,}\s*">
<!-- two spaces at end of line generates linebreak -->
<!ENTITY linebreakregex " $">
<!ENTITY strikeoutregex "[~]{2}[^~].*[^~][~]{2}">
<!-- pandoc style -->
]>
<language name="Markdown" version="3" kateversion="3.8" section="Markup" extensions="*.md;*.mmd;*.markdown" priority="15" author="Darrin Yeager, Claes Holmerson" license="GPL,BSD">
<highlighting>
<contexts>
<context attribute="Normal Text" lineEndContext="#stay" name="Normal Text">
<DetectChar context="blockquote" char="&gt;" column="0"/>
<RegExpr attribute="h1" String="^#\s.*[#]?$"/>
<RegExpr attribute="h2" String="^##\s.*[#]?$"/>
<RegExpr attribute="h3" String="^###\s.*[#]?$"/>
<RegExpr attribute="h4" String="^####\s.*[#]?$"/>
<RegExpr attribute="h5" String="^#####\s.*[#]?$"/>
<RegExpr attribute="h6" String="^######\s.*[#]?$"/>
<RegExpr attribute="ruler" String="&rulerregex;"/>
<RegExpr attribute="strong" String="&strongregex;"/>
<RegExpr attribute="emphasis" String="&emphasisregex;"/>
<RegExpr attribute="strongemphasis" String="&strongemphasisregex;"/>
<RegExpr attribute="code" String="^([\s]{4,}|\t+).*$"/>
<RegExpr context="bullet" String="^[\*\+\-]\s"/>
<RegExpr context="numlist" String="^[\d]+\.\s"/>
<RegExpr attribute="meta" String="^(Title|Author|Date|Copyright|Revision|CSS|LaTeX\ XSLT|Categories|Tags|BaseName|Excerpt):(.*)+$"/>
<IncludeRules context="inc"/>
</context>
<context attribute="blockquote" lineEndContext="#stay" lineEmptyContext="#pop" name="blockquote">
<RegExpr attribute="bq-strong" String="&strongregex;"/>
<RegExpr attribute="bq-emphasis" String="&emphasisregex;"/>
<IncludeRules context="inc"/>
</context>
<context attribute="bullet" lineEndContext="#stay" lineEmptyContext="#pop" name="bullet">
<RegExpr attribute="bl-strong" String="&strongregex;"/>
<RegExpr attribute="bl-emphasis" String="&emphasisregex;"/>
<IncludeRules context="inc"/>
</context>
<context attribute="numlist" lineEndContext="#stay" lineEmptyContext="#pop" name="numlist">
<RegExpr attribute="nl-strong" String="&strongregex;"/>
<RegExpr attribute="nl-emphasis" String="&emphasisregex;"/>
<IncludeRules context="inc"/>
</context>
<context attribute="comment" lineEndContext="#stay" name="comment">
<RegExpr String="--&gt;" attribute="comment" context="#pop" endRegion="comment"/>
</context>
<context attribute="code" lineEndContext="#stay" name="php-code">
<WordDetect attribute="code" context="#pop" String="```"/>
<IncludeRules context="phpsource##PHP/PHP"/>
</context>
<context attribute="code" lineEndContext="#stay" name="python-code">
<WordDetect attribute="code" context="#pop" String="```"/>
<IncludeRules context="##Python"/>
</context>
<context attribute="code" lineEndContext="#stay" name="code">
<WordDetect attribute="code" context="#pop" String="```"/>
</context>
<context attribute="common" name="inc" lineEndContext="#stay">
<RegExpr attribute="code" String="`[^`]+`"/>
<RegExpr context="comment" String="&lt;!--" beginRegion="comment"/>
<RegExpr attribute="reflink" String="&reflinkregex;"/>
<RegExpr attribute="footnote" String="&footnoteregex;"/>
<RegExpr attribute="inlinelink" String="&inlinelinkregex;"/>
<RegExpr attribute="reflinktarget" String="&reflinktargetregex;"/>
<RegExpr attribute="inlineimage" String="&inlineimageregex;"/>
<RegExpr attribute="refimage" String="&refimageregex;"/>
<RegExpr attribute="autolink" String="&autolinkregex;"/>
<RegExpr attribute="mailtolink" String="&mailtolinkregex;"/>
<RegExpr attribute="strikeout" minimal="true" String="&strikeoutregex;"/>
<RegExpr attribute="linebreak" minimal="true" String="&linebreakregex;"/>
<WordDetect attribute="code" context="php-code" String="```php"/>
<WordDetect attribute="code" context="python-code" String="```python"/>
<StringDetect attribute="code" context="code" String="```"/>
</context>
</contexts>
<itemDatas>
<itemData name="Normal Text" defStyleNum="dsNormal"/>
<itemData name="common" defStyleNum="dsNormal"/>
<itemData name="strongemphasis" defStyleNum="dsNormal" italic="true" bold="true"/>
<itemData name="emphasis" defStyleNum="dsNormal" italic="true"/>
<itemData name="strong" defStyleNum="dsNormal" bold="true"/>
<itemData name="ruler" defStyleNum="dsNormal" bold="true"/>
<itemData name="strikeout" defStyleNum="dsNormal" strikeOut="true"/>
<itemData name="linebreak" defStyleNum="dsNormal" underline="true" color="#999999"/>
<itemData name="h1" defStyleNum="dsFunction" bold="true"/>
<itemData name="h2" defStyleNum="dsFunction" bold="true"/>
<itemData name="h3" defStyleNum="dsFunction" bold="true"/>
<itemData name="h4" defStyleNum="dsFunction" bold="true"/>
<itemData name="h5" defStyleNum="dsFunction" bold="true"/>
<itemData name="h6" defStyleNum="dsFunction" bold="true"/>
<itemData name="blockquote" defStyleNum="dsDataType"/>
<itemData name="bq-emphasis" defStyleNum="dsDataType" italic="true"/>
<itemData name="bq-strong" defStyleNum="dsDataType" bold="true"/>
<itemData name="bullet" defStyleNum="dsFloat"/>
<itemData name="bl-emphasis" defStyleNum="dsFloat" italic="true"/>
<itemData name="bl-strong" defStyleNum="dsFloat" bold="true"/>
<itemData name="numlist" defStyleNum="dsFloat"/>
<itemData name="nl-emphasis" defStyleNum="dsFloat" italic="true"/>
<itemData name="nl-strong" defStyleNum="dsFloat" bold="true"/>
<itemData name="comment" defStyleNum="dsComment"/>
<itemData name="code" defStyleNum="dsBaseN"/>
<itemData name="reflink" defStyleNum="dsOthers" underline="true"/>
<itemData name="inlinelink" defStyleNum="dsOthers" underline="true"/>
<itemData name="autolink" defStyleNum="dsOthers" underline="true"/>
<itemData name="mailtolink" defStyleNum="dsOthers" underline="true"/>
<itemData name="footnote" defStyleNum="dsOthers" italic="true"/>
<itemData name="meta" defStyleNum="dsComment"/>
<itemData name="reflinktarget" defStyleNum="dsOthers" italic="false" bold="false"/>
<itemData name="inlineimage" defStyleNum="dsAlert" italic="false" bold="false"/>
<itemData name="refimage" defStyleNum="dsAlert" italic="false" bold="false"/>
</itemDatas>
</highlighting>
<general>
<comments>
<comment name="multiLine" start="&lt;!--" end="--&gt;" region="comment"/>
</comments>
</general>
</language>

View File

@@ -0,0 +1,934 @@
<!DOCTYPE language SYSTEM "language.dtd">
<language
name="PowerShell"
version="4"
kateversion="5.0"
extensions="*.ps1;*.ps1m;*.ps1d"
section="Scripts"
author="Motoki Kashihara (motoki8791@gmail.com); Michael Lombardi (Michael.T.Lombardi@outlook.com)"
casesensitive="0"
license="MIT">
<highlighting>
<list name="keywords">
<item>Begin</item>
<item>Exit</item>
<item>Process</item>
<item>Break</item>
<item>Filter</item>
<item>Return</item>
<item>Catch</item>
<item>Finally</item>
<item>Sequence</item>
<item>Class</item>
<item>For</item>
<item>Switch</item>
<item>Continue</item>
<item>ForEach</item>
<item>Throw</item>
<item>Data</item>
<item>From</item>
<item>Trap</item>
<item>Define</item>
<item>Function</item>
<item>Try</item>
<item>Do</item>
<item>If</item>
<item>Until</item>
<item>DynamicParam</item>
<item>In</item>
<item>Using</item>
<item>Else</item>
<item>InlineScript</item>
<item>Var</item>
<item>ElseIf</item>
<item>Parallel</item>
<item>While</item>
<item>End</item>
<item>Param</item>
<item>Workflow</item>
</list>
<!-- TODO: Seems unused?!
<list name="attributes">
<item>CmdletBinding</item>
<item>ConfirmImpact</item>
<item>DefaultParameterSetName</item>
<item>HelpURI</item>
<item>SupportsPaging</item>
<item>SupportsShouldProcess</item>
<item>PositionalBinding</item>
</list>-->
<list name="types">
<item>bool</item>
<item>byte</item>
<item>char</item>
<item>decimal</item>
<item>double</item>
<item>float</item>
<item>int</item>
<item>long</item>
<item>object</item>
<item>sbyte</item>
<item>short</item>
<item>string</item>
<item>switch</item>
<item>uint</item>
<item>ulong</item>
<item>ushort</item>
</list>
<!-- TODO: Seems unused?!
<list name="operators">
<item>-split</item>
<item>-isplit</item>
<item>-csplit</item>
<item>-join</item>
<item>-is</item>
<item>-isnot</item>
<item>-as</item>
<item>-eq</item>
<item>-ieq</item>
<item>-ceq</item>
<item>-ne</item>
<item>-ine</item>
<item>-cne</item>
<item>-gt</item>
<item>-igt</item>
<item>-cgt</item>
<item>-ge</item>
<item>-ige</item>
<item>-cge</item>
<item>-lt</item>
<item>-ilt</item>
<item>-clt</item>
<item>-le</item>
<item>-ile</item>
<item>-cle</item>
<item>-like</item>
<item>-ilike</item>
<item>-clike</item>
<item>-notlike</item>
<item>-inotlike</item>
<item>-cnotlike</item>
<item>-match</item>
<item>-imatch</item>
<item>-cmatch</item>
<item>-notmatch</item>
<item>-inotmatch</item>
<item>-cnotmatch</item>
<item>-contains</item>
<item>-icontains</item>
<item>-ccontains</item>
<item>-notcontains</item>
<item>-inotcontains</item>
<item>-cnotcontains</item>
<item>-replace</item>
<item>-ireplace</item>
<item>-creplace</item>
<item>-band</item>
<item>-bor</item>
<item>-bxor</item>
<item>-and</item>
<item>-or</item>
<item>-xor</item>
<item>.</item>
<item>&amp;</item>
<item>=</item>
<item>+=</item>
<item>-=</item>
<item>*=</item>
<item>/=</item>
<item>%=</item>
</list>-->
<list name="cmdlets">
<item>Add-Content</item>
<item>Add-ADComputerServiceAccount</item>
<item>Add-ADDomainControllerPasswordReplicationPolicy</item>
<item>Add-ADFineGrainedPasswordPolicySubject</item>
<item>Add-ADGroupMember</item>
<item>Add-ADPrincipalGroupMembership</item>
<item>Add-BitsFile</item>
<item>Add-ClusterDisk</item>
<item>Add-ClusterFileServerRole</item>
<item>Add-ClusterGenericApplicationRole</item>
<item>Add-ClusterGenericScriptRole</item>
<item>Add-ClusterGenericServiceRole</item>
<item>Add-ClusterGroup</item>
<item>Add-ClusterNode</item>
<item>Add-ClusterPrintServerRole</item>
<item>Add-ClusterResource</item>
<item>Add-ClusterResourceDependency</item>
<item>Add-ClusterResourceType</item>
<item>Add-ClusterServerRole</item>
<item>Add-ClusterSharedVolume</item>
<item>Add-ClusterVirtualMachineRole</item>
<item>Add-Computer</item>
<item>Add-Content</item>
<item>Add-History</item>
<item>Add-JobTrigger</item>
<item>Add-Member</item>
<item>Add-NlbClusterNode</item>
<item>Add-NlbClusterNodeDip</item>
<item>Add-NlbClusterPortRule</item>
<item>Add-NlbClusterVip</item>
<item>Add-PSSnapin</item>
<item>Add-Type</item>
<item>Backup-GPO</item>
<item>Block-ClusterAccess</item>
<item>Checkpoint-Computer</item>
<item>Clear-ADAccountExpiration</item>
<item>Clear-ClusterDiskReservation</item>
<item>Clear-ClusterNode</item>
<item>Clear-Content</item>
<item>Clear-EventLog</item>
<item>Clear-History</item>
<item>Clear-Item</item>
<item>Clear-ItemProperty</item>
<item>Clear-RecycleBin</item>
<item>Clear-Variable</item>
<item>Compare-Object</item>
<item>Complete-BitsTransfer</item>
<item>Complete-Transaction</item>
<item>Connect-PSSession</item>
<item>Connect-WSMan</item>
<item>ConvertFrom-Csv</item>
<item>ConvertFrom-Json</item>
<item>ConvertFrom-SecureString</item>
<item>ConvertFrom-String</item>
<item>ConvertFrom-StringData</item>
<item>Convert-Path</item>
<item>Convert-String</item>
<item>ConvertTo-Csv</item>
<item>ConvertTo-Html</item>
<item>ConvertTo-Json</item>
<item>ConvertTo-SecureString</item>
<item>ConvertTo-Xml</item>
<item>Copy-GPO</item>
<item>Copy-Item</item>
<item>Copy-ItemProperty</item>
<item>Debug-Job</item>
<item>Debug-Process</item>
<item>Debug-Runspace</item>
<item>Disable-ADAccount</item>
<item>Disable-ADOptionalFeature</item>
<item>Disable-ComputerRestore</item>
<item>Disable-JobTrigger</item>
<item>Disable-NlbClusterPortRule</item>
<item>Disable-PSBreakpoint</item>
<item>Disable-PSRemoting</item>
<item>Disable-PSSessionConfiguration</item>
<item>Disable-RunspaceDebug</item>
<item>Disable-ScheduledJob</item>
<item>Disable-WSManCredSSP</item>
<item>Disconnect-PSSession</item>
<item>Disconnect-WSMan</item>
<item>Enable-ADAccount</item>
<item>Enable-ADOptionalFeature</item>
<item>Enable-ComputerRestore</item>
<item>Enable-JobTrigger</item>
<item>Enable-NlbClusterPortRule</item>
<item>Enable-PSBreakpoint</item>
<item>Enable-PSRemoting</item>
<item>Enable-PSSessionConfiguration</item>
<item>Enable-RunspaceDebug</item>
<item>Enable-ScheduledJob</item>
<item>Enable-WSManCredSSP</item>
<item>Enter-PSHostProcess</item>
<item>Enter-PSSession</item>
<item>Exit-PSHostProcess</item>
<item>Exit-PSSession</item>
<item>Export-Alias</item>
<item>Export-BinaryMiLog</item>
<item>Export-Clixml</item>
<item>Export-Console</item>
<item>Export-Counter</item>
<item>Export-Csv</item>
<item>Export-FormatData</item>
<item>Export-ModuleMember</item>
<item>Export-PSSession</item>
<item>Find-Package</item>
<item>Find-PackageProvider</item>
<item>ForEach-Object</item>
<item>Format-Custom</item>
<item>Format-List</item>
<item>Format-Table</item>
<item>Format-Wide</item>
<item>Get-Acl</item>
<item>Get-ADAccountAuthorizationGroup</item>
<item>Get-ADAccountResultantPasswordReplicationPolicy</item>
<item>Get-ADComputer</item>
<item>Get-ADComputerServiceAccount</item>
<item>Get-ADDefaultDomainPasswordPolicy</item>
<item>Get-ADDomain</item>
<item>Get-ADDomainController</item>
<item>Get-ADDomainControllerPasswordReplicationPolicy</item>
<item>Get-ADDomainControllerPasswordReplicationPolicyUsage</item>
<item>Get-ADFineGrainedPasswordPolicy</item>
<item>Get-ADFineGrainedPasswordPolicySubject</item>
<item>Get-ADForest</item>
<item>Get-ADGroup</item>
<item>Get-ADGroupMember</item>
<item>Get-ADObject</item>
<item>Get-ADOptionalFeature</item>
<item>Get-ADOrganizationalUnit</item>
<item>Get-ADPrincipalGroupMembership</item>
<item>Get-ADRootDSE</item>
<item>Get-ADServiceAccount</item>
<item>Get-ADUser</item>
<item>Get-ADUserResultantPasswordPolicy</item>
<item>Get-Alias</item>
<item>Get-AppLockerFileInformation</item>
<item>Get-AppLockerPolicy</item>
<item>Get-AuthenticodeSignature</item>
<item>Get-BitsTransfer</item>
<item>Get-ChildItem</item>
<item>Get-CimAssociatedInstance</item>
<item>Get-CimClass</item>
<item>Get-CimInstance</item>
<item>Get-CimSession</item>
<item>Get-Clipboard</item>
<item>Get-Cluster</item>
<item>Get-ClusterAccess</item>
<item>Get-ClusterAvailableDisk</item>
<item>Get-ClusterGroup</item>
<item>Get-ClusterLog</item>
<item>Get-ClusterNetwork</item>
<item>Get-ClusterNetworkInterfac</item>
<item>Get-ClusterNode</item>
<item>Get-ClusterOwnerNode</item>
<item>Get-ClusterParameter</item>
<item>Get-ClusterQuorum</item>
<item>Get-ClusterResource</item>
<item>Get-ClusterResourceDependency</item>
<item>Get-ClusterResourceDependencyReport</item>
<item>Get-ClusterResourceType</item>
<item>Get-ClusterSharedVolume</item>
<item>Get-CmsMessage</item>
<item>Get-Command</item>
<item>Get-ComputerRestorePoint</item>
<item>Get-Content</item>
<item>Get-ControlPanelItem</item>
<item>Get-Counter</item>
<item>Get-Credential</item>
<item>Get-Culture</item>
<item>Get-Date</item>
<item>Get-Event</item>
<item>Get-EventLog</item>
<item>Get-EventSubscriber</item>
<item>Get-ExecutionPolicy</item>
<item>Get-FormatData</item>
<item>Get-GPInheritance</item>
<item>Get-GPO</item>
<item>Get-GPOReport</item>
<item>Get-GPPermissions</item>
<item>Get-GPPrefRegistryValue</item>
<item>Get-GPRegistryValue</item>
<item>Get-GPResultantSetOfPolicy</item>
<item>Get-GPStarterGPO</item>
<item>Get-Help</item>
<item>Get-History</item>
<item>Get-Host</item>
<item>Get-HotFix</item>
<item>Get-Item</item>
<item>Get-ItemProperty</item>
<item>Get-ItemPropertyValue</item>
<item>Get-Job</item>
<item>Get-JobTrigger</item>
<item>Get-Location</item>
<item>Get-Member</item>
<item>Get-Module</item>
<item>Get-NlbCluster</item>
<item>Get-NlbClusterDriverInfo</item>
<item>Get-NlbClusterNode</item>
<item>Get-NlbClusterNodeDip</item>
<item>Get-NlbClusterNodeNetworkInterface</item>
<item>Get-NlbClusterPortRule</item>
<item>Get-NlbClusterVip</item>
<item>Get-Package</item>
<item>Get-PackageProvider</item>
<item>Get-PackageSource</item>
<item>Get-PfxCertificate</item>
<item>Get-Process</item>
<item>Get-PSBreakpoint</item>
<item>Get-PSCallStack</item>
<item>Get-PSDrive</item>
<item>Get-PSHostProcessInfo</item>
<item>Get-PSProvider</item>
<item>Get-PSReadlineKeyHandler</item>
<item>Get-PSReadlineOption</item>
<item>Get-PSSession</item>
<item>Get-PSSessionCapability</item>
<item>Get-PSSessionConfiguration</item>
<item>Get-PSSnapin</item>
<item>Get-Random</item>
<item>Get-Runspace</item>
<item>Get-RunspaceDebug</item>
<item>Get-ScheduledJob</item>
<item>Get-ScheduledJobOption</item>
<item>Get-Service</item>
<item>Get-TraceSource</item>
<item>Get-Transaction</item>
<item>Get-TroubleshootingPack</item>
<item>Get-TypeData</item>
<item>Get-UICulture</item>
<item>Get-Unique</item>
<item>Get-Variable</item>
<item>Get-WinEvent</item>
<item>Get-WmiObject</item>
<item>Get-WSManCredSSP</item>
<item>Get-WSManInstance</item>
<item>Grant-ClusterAccess</item>
<item>Group-Object</item>
<item>Import-Alias</item>
<item>Import-BinaryMiLog</item>
<item>Import-Clixml</item>
<item>Import-Counter</item>
<item>Import-Csv</item>
<item>Import-GPO</item>
<item>Import-LocalizedData</item>
<item>Import-Module</item>
<item>Import-PackageProvider</item>
<item>Import-PSSession</item>
<item>Install-ADServiceAccount</item>
<item>Install-Package</item>
<item>Install-PackageProvider</item>
<item>Invoke-CimMethod</item>
<item>Invoke-Command</item>
<item>Invoke-DscResource</item>
<item>Invoke-Expression</item>
<item>Invoke-History</item>
<item>Invoke-Item</item>
<item>Invoke-RestMethod</item>
<item>Invoke-TroubleshootingPack</item>
<item>Invoke-WebRequest</item>
<item>Invoke-WmiMethod</item>
<item>Invoke-WSManAction</item>
<item>Join-Path</item>
<item>Limit-EventLog</item>
<item>Measure-Command</item>
<item>Measure-Object</item>
<item>Move-ADDirectoryServer</item>
<item>Move-ADDirectoryServerOperationMasterRole</item>
<item>Move-ADObject</item>
<item>Move-ClusterGroup</item>
<item>Move-ClusterResource</item>
<item>Move-ClusterSharedVolume</item>
<item>Move-ClusterVirtualMachineRole</item>
<item>Move-Item</item>
<item>Move-ItemProperty</item>
<item>New-ADComputer</item>
<item>New-ADFineGrainedPasswordPolicy</item>
<item>New-ADGroup</item>
<item>New-ADObject</item>
<item>New-ADOrganizationalUnit</item>
<item>New-ADServiceAccount</item>
<item>New-ADUser</item>
<item>New-Alias</item>
<item>New-AppLockerPolicy</item>
<item>New-CimInstance</item>
<item>New-CimSession</item>
<item>New-CimSessionOption</item>
<item>New-Cluster</item>
<item>New-Event</item>
<item>New-EventLog</item>
<item>New-GPLink</item>
<item>New-GPO</item>
<item>New-GPStarterGPO</item>
<item>New-Item</item>
<item>New-ItemProperty</item>
<item>New-JobTrigger</item>
<item>New-Module</item>
<item>New-ModuleManifest</item>
<item>New-NlbCluster</item>
<item>New-NlbClusterIpv6Address</item>
<item>New-Object</item>
<item>New-PSDrive</item>
<item>New-PSRoleCapabilityFile</item>
<item>New-PSSession</item>
<item>New-PSSessionConfigurationFile</item>
<item>New-PSSessionOption</item>
<item>New-PSTransportOption</item>
<item>New-PSWorkflowExecutionOption</item>
<item>New-ScheduledJobOption</item>
<item>New-Service</item>
<item>New-TimeSpan</item>
<item>New-Variable</item>
<item>New-WebServiceProxy</item>
<item>New-WinEvent</item>
<item>New-WSManInstance</item>
<item>New-WSManSessionOption</item>
<item>Out-Default</item>
<item>Out-File</item>
<item>Out-GridView</item>
<item>Out-Host</item>
<item>Out-Null</item>
<item>Out-Printer</item>
<item>Out-String</item>
<item>Pop-Location</item>
<item>Protect-CmsMessage</item>
<item>Publish-DscConfiguration</item>
<item>Push-Location</item>
<item>Read-Host</item>
<item>Receive-Job</item>
<item>Receive-PSSession</item>
<item>Register-ArgumentCompleter</item>
<item>Register-CimIndicationEvent</item>
<item>Register-EngineEvent</item>
<item>Register-ObjectEvent</item>
<item>Register-PackageSource</item>
<item>Register-PSSessionConfiguration</item>
<item>Register-ScheduledJob</item>
<item>Register-WmiEvent</item>
<item>Remove-ADComputer</item>
<item>Remove-ADComputerServiceAccount</item>
<item>Remove-ADDomainControllerPasswordReplicationPolicy</item>
<item>Remove-ADFineGrainedPasswordPolicy</item>
<item>Remove-ADFineGrainedPasswordPolicySubject</item>
<item>Remove-ADGroup</item>
<item>Remove-ADGroupMember</item>
<item>Remove-ADObject</item>
<item>Remove-ADOrganizationalUnit</item>
<item>Remove-ADPrincipalGroupMembership</item>
<item>Remove-ADServiceAccount</item>
<item>Remove-ADUser</item>
<item>Remove-BitsTransfer</item>
<item>Remove-CimInstance</item>
<item>Remove-CimSession</item>
<item>Remove-Cluster</item>
<item>Remove-ClusterAccess</item>
<item>Remove-ClusterGroup</item>
<item>Remove-ClusterNode</item>
<item>Remove-ClusterResource</item>
<item>Remove-ClusterResourceDependency</item>
<item>Remove-ClusterResourceType</item>
<item>Remove-ClusterSharedVolume</item>
<item>Remove-Computer</item>
<item>Remove-Event</item>
<item>Remove-EventLog</item>
<item>Remove-GPLink</item>
<item>Remove-GPO</item>
<item>Remove-GPPrefRegistryValue</item>
<item>Remove-GPRegistryValue</item>
<item>Remove-Item</item>
<item>Remove-ItemProperty</item>
<item>Remove-Job</item>
<item>Remove-JobTrigger</item>
<item>Remove-Module</item>
<item>Remove-NlbCluster</item>
<item>Remove-NlbClusterNode</item>
<item>Remove-NlbClusterNodeDip</item>
<item>Remove-NlbClusterPortRule</item>
<item>Remove-NlbClusterVip</item>
<item>Remove-PSBreakpoint</item>
<item>Remove-PSDrive</item>
<item>Remove-PSReadlineKeyHandler</item>
<item>Remove-PSSession</item>
<item>Remove-PSSnapin</item>
<item>Remove-TypeData</item>
<item>Remove-Variable</item>
<item>Remove-WmiObject</item>
<item>Remove-WSManInstance</item>
<item>Rename-ADObject</item>
<item>Rename-Computer</item>
<item>Rename-GPO</item>
<item>Rename-Item</item>
<item>Rename-ItemProperty</item>
<item>Repair-ClusterSharedVolume</item>
<item>Reset-ADServiceAccountPassword</item>
<item>Reset-ComputerMachinePassword</item>
<item>Resolve-Path</item>
<item>Restart-Computer</item>
<item>Restart-Service</item>
<item>Restore-ADObject</item>
<item>Restore-Computer</item>
<item>Restore-GPO</item>
<item>Resume-BitsTransfer</item>
<item>Resume-ClusterNode</item>
<item>Resume-ClusterResource</item>
<item>Resume-Job</item>
<item>Resume-NlbCluster</item>
<item>Resume-NlbClusterNode</item>
<item>Resume-Service</item>
<item>Save-Help</item>
<item>Save-Package</item>
<item>Search-ADAccount</item>
<item>Select-Object</item>
<item>Select-String</item>
<item>Select-Xml</item>
<item>Send-MailMessage</item>
<item>Set-Acl</item>
<item>Set-ADAccountControl</item>
<item>Set-ADAccountExpiration</item>
<item>Set-ADAccountPassword</item>
<item>Set-ADComputer</item>
<item>Set-ADDefaultDomainPasswordPolicy</item>
<item>Set-ADDomain</item>
<item>Set-ADDomainMode</item>
<item>Set-ADFineGrainedPasswordPolicy</item>
<item>Set-ADForest</item>
<item>Set-ADForestMode</item>
<item>Set-ADGroup</item>
<item>Set-ADObject</item>
<item>Set-ADOrganizationalUnit</item>
<item>Set-ADServiceAccount</item>
<item>Set-ADUser</item>
<item>Set-Alias</item>
<item>Set-AppLockerPolicy</item>
<item>Set-AuthenticodeSignature</item>
<item>Set-BitsTransfer</item>
<item>Set-CimInstance</item>
<item>Set-Clipboard</item>
<item>Set-ClusterLog</item>
<item>Set-ClusterOwnerNode</item>
<item>Set-ClusterParameter</item>
<item>Set-ClusterQuorum</item>
<item>Set-ClusterResourceDependency</item>
<item>Set-Content</item>
<item>Set-Date</item>
<item>Set-DscLocalConfigurationManager</item>
<item>Set-ExecutionPolicy</item>
<item>Set-GPInheritance</item>
<item>Set-GPLink</item>
<item>Set-GPPermissions</item>
<item>Set-GPPrefRegistryValue</item>
<item>Set-GPRegistryValue</item>
<item>Set-Item</item>
<item>Set-ItemProperty</item>
<item>Set-JobTrigger</item>
<item>Set-Location</item>
<item>Set-NlbCluster</item>
<item>Set-NlbClusterNode</item>
<item>Set-NlbClusterNodeDip</item>
<item>Set-NlbClusterPortRule</item>
<item>Set-NlbClusterPortRuleNodeHandlingPriority</item>
<item>Set-NlbClusterPortRuleNodeWeight</item>
<item>Set-NlbClusterVip</item>
<item>Set-PackageSource</item>
<item>Set-PSBreakpoint</item>
<item>Set-PSDebug</item>
<item>Set-PSReadlineKeyHandler</item>
<item>Set-PSReadlineOption</item>
<item>Set-PSSessionConfiguration</item>
<item>Set-ScheduledJob</item>
<item>Set-ScheduledJobOption</item>
<item>Set-Service</item>
<item>Set-StrictMode</item>
<item>Set-TraceSource</item>
<item>Set-Variable</item>
<item>Set-WmiInstance</item>
<item>Set-WSManInstance</item>
<item>Set-WSManQuickConfig</item>
<item>Show-Command</item>
<item>Show-ControlPanelItem</item>
<item>Show-EventLog</item>
<item>Sort-Object</item>
<item>Split-Path</item>
<item>Start-BitsTransfer</item>
<item>Start-Cluster</item>
<item>Start-ClusterGroup</item>
<item>Start-ClusterNode</item>
<item>Start-ClusterResource</item>
<item>Start-DscConfiguration</item>
<item>Start-Job</item>
<item>Start-NlbCluster</item>
<item>Start-NlbClusterNode</item>
<item>Start-Process</item>
<item>Start-Service</item>
<item>Start-Sleep</item>
<item>Start-Transaction</item>
<item>Start-Transcript</item>
<item>Stop-Cluster</item>
<item>Stop-ClusterGroup</item>
<item>Stop-ClusterNode</item>
<item>Stop-ClusterResource</item>
<item>Stop-Computer</item>
<item>Stop-Job</item>
<item>Stop-NlbCluster</item>
<item>Stop-NlbClusterNode</item>
<item>Stop-Process</item>
<item>Stop-Service</item>
<item>Stop-Transcript</item>
<item>Suspend-BitsTransfer</item>
<item>Suspend-ClusterNode</item>
<item>Suspend-ClusterResource</item>
<item>Suspend-Job</item>
<item>Suspend-NlbCluster</item>
<item>Suspend-NlbClusterNode</item>
<item>Suspend-Service</item>
<item>Tee-Object</item>
<item>Test-AppLockerPolicy</item>
<item>Test-Cluster</item>
<item>Test-ClusterResourceFailure</item>
<item>Test-ComputerSecureChannel</item>
<item>Test-Connection</item>
<item>Test-DscConfiguration</item>
<item>Test-ModuleManifest</item>
<item>Test-Path</item>
<item>Test-PSSessionConfigurationFile</item>
<item>Test-WSMan</item>
<item>Trace-Command</item>
<item>Unblock-File</item>
<item>Undo-Transaction</item>
<item>Uninstall-ADServiceAccount</item>
<item>Uninstall-Package</item>
<item>Unlock-ADAccount</item>
<item>Unprotect-CmsMessage</item>
<item>Unregister-Event</item>
<item>Unregister-PackageSource</item>
<item>Unregister-PSSessionConfiguration</item>
<item>Unregister-ScheduledJob</item>
<item>Update-ClusterIPResource</item>
<item>Update-ClusterVirtualMachineConfiguration</item>
<item>Update-FormatData</item>
<item>Update-Help</item>
<item>Update-List</item>
<item>Update-TypeData</item>
<item>Use-Transaction</item>
<item>Wait-Debugger</item>
<item>Wait-Event</item>
<item>Wait-Job</item>
<item>Wait-Process</item>
<item>Where-Object</item>
<item>Write-Debug</item>
<item>Write-Error</item>
<item>Write-EventLog</item>
<item>Write-Host</item>
<item>Write-Information</item>
<item>Write-Output</item>
<item>Write-Progress</item>
<item>Write-Verbose</item>
<item>Write-Warning</item>
<item>ac</item>
<item>asnp</item>
<item>cat</item>
<item>cd</item>
<item>chdir</item>
<item>clc</item>
<item>clear</item>
<item>clhy</item>
<item>cli</item>
<item>clp</item>
<item>cls</item>
<item>clv</item>
<item>cnsn</item>
<item>compare</item>
<item>copy</item>
<item>cp</item>
<item>cpi</item>
<item>cpp</item>
<item>curl</item>
<item>cvpa</item>
<item>dbp</item>
<item>del</item>
<item>diff</item>
<item>dir</item>
<item>dnsn</item>
<item>ebp</item>
<item>echo</item>
<item>epal</item>
<item>epcsv</item>
<item>epsn</item>
<item>erase</item>
<item>etsn</item>
<item>exsn</item>
<item>fc</item>
<item>fl</item>
<item>foreach</item>
<item>ft</item>
<item>fw</item>
<item>gal</item>
<item>gbp</item>
<item>gc</item>
<item>gci</item>
<item>gcm</item>
<item>gcs</item>
<item>gdr</item>
<item>ghy</item>
<item>gi</item>
<item>gjb</item>
<item>gl</item>
<item>gm</item>
<item>gmo</item>
<item>gp</item>
<item>gps</item>
<item>group</item>
<item>gsn</item>
<item>gsnp</item>
<item>gsv</item>
<item>gu</item>
<item>gv</item>
<item>gwmi</item>
<item>h</item>
<item>history</item>
<item>icm</item>
<item>iex</item>
<item>ihy</item>
<item>ii</item>
<item>ipal</item>
<item>ipcsv</item>
<item>ipmo</item>
<item>ipsn</item>
<item>irm</item>
<item>ise</item>
<item>iwmi</item>
<item>iwr</item>
<item>kill</item>
<item>lp</item>
<item>ls</item>
<item>man</item>
<item>md</item>
<item>measure</item>
<item>mi</item>
<item>mount</item>
<item>move</item>
<item>mp</item>
<item>mv</item>
<item>nal</item>
<item>ndr</item>
<item>ni</item>
<item>nmo</item>
<item>npssc</item>
<item>nsn</item>
<item>nv</item>
<item>ogv</item>
<item>oh</item>
<item>popd</item>
<item>ps</item>
<item>pushd</item>
<item>pwd</item>
<item>r</item>
<item>rbp</item>
<item>rcjb</item>
<item>rcsn</item>
<item>rd</item>
<item>rdr</item>
<item>ren</item>
<item>ri</item>
<item>rjb</item>
<item>rm</item>
<item>rmdir</item>
<item>rmo</item>
<item>rni</item>
<item>rnp</item>
<item>rp</item>
<item>rsn</item>
<item>rsnp</item>
<item>rujb</item>
<item>rv</item>
<item>rvpa</item>
<item>rwmi</item>
<item>sajb</item>
<item>sal</item>
<item>saps</item>
<item>sasv</item>
<item>sbp</item>
<item>sc</item>
<item>select</item>
<item>set</item>
<item>shcm</item>
<item>si</item>
<item>sl</item>
<item>sleep</item>
<item>sls</item>
<item>sort</item>
<item>sp</item>
<item>spjb</item>
<item>spps</item>
<item>spsv</item>
<item>start</item>
<item>sujb</item>
<item>sv</item>
<item>swmi</item>
<item>tee</item>
<item>trcm</item>
<item>type</item>
<item>wget</item>
<item>where</item>
<item>wjb</item>
<item>write</item>
<item>\%</item>
<item>\?</item>
</list>
<list name="special-variables">
<item>$_</item>
<item>$True</item>
<item>$False</item>
<item>$Env</item>
<item>$Null</item>
<item>$^</item>
<item>$$</item>
<item>$?</item>
<item>$input</item>
<item>$foreach</item>
<item>$args</item>
<item>$switch</item>
<item>$matches</item>
<item>$LastExitCode</item>
<item>$Error</item>
<item>$StackTrace</item>
<item>$HOME</item>
<item>$PsHome</item>
<item>$ConsoleFileName</item>
<item>$PWD</item>
<item>$ShellId</item>
<item>$Profile</item>
<item>$Host</item>
<item>$OFS</item>
</list>
<contexts>
<context attribute="Normal Text" lineEndContext="#stay" name="Normal">
<keyword attribute="Keyword" context="#stay" String="keywords"/>
<keyword attribute="Data Type" context="#stay" String="types" />
<IncludeRules context="Cmdlet" />
<DetectChar attribute="String" context="String" char="&quot;"/>
<Detect2Chars attribute="HereString" context="HereStringer" char="@" char1="&quot;" beginRegion="StringRegion"/>
<IncludeRules context="##Doxygen" />
<DetectChar attribute="Comment" context="Commentar 1" char="#"/>
<Detect2Chars attribute="Comment" context="Commentar 2" char="&lt;" char1="#" beginRegion="CommentRegion"/>
<DetectChar attribute="Symbol" context="#stay" char="{" beginRegion="block1"/>
<DetectChar attribute="Symbol" context="#stay" char="}" endRegion="block1"/>
<RegExpr attribute="Keyword" context="#stay" String="\b\$global(?=\s+(:))"/>
<RegExpr attribute="Keyword" context="#stay" String="\b\$script(?=\s+(:))"/>
<RegExpr attribute="Variable" context="#stay" String="\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*" />
<keyword attribute="Special Variable" context="#stay" String="special-variables"/>
<RegExpr attribute="Symbol" context="Member" String="[.]{1,1}" />
<AnyChar attribute="Symbol" context="#stay" String=":!%&amp;()+,-/.*&lt;=&gt;?[]|~^&#59;"/>
</context>
<context attribute="String" lineEndContext="#pop" name="String">
<LineContinue attribute="String" context="#pop"/>
<DetectChar attribute="String" context="#pop" char="&quot;"/>
</context>
<context attribute="HereString" lineEndContext="#stay" name="HereStringer">
<Detect2Chars attribute="HereString" context="#pop" char="&quot;" char1="@" endRegion="StringRegion"/>
</context>
<context attribute="Normal Text" lineEndContext="#pop" name="Member" fallthrough="true" fallthroughContext="#pop">
<RegExpr attribute="Function" context="#pop" String="\b[_\w][_\w\d]*(?=[\s]*)" />
</context>
<context attribute="Comment" lineEndContext="#pop" name="Commentar 1"/>
<context attribute="Comment" lineEndContext="#stay" name="Commentar 2">
<Detect2Chars attribute="Comment" context="#pop" char="#" char1="&gt;" endRegion="CommentRegion"/>
</context>
<context attribute="Cmdlets" lineEndContext="#stay" name="Cmdlet">
<keyword attribute="Function" context="#stay" String="cmdlets"/>
</context>
</contexts>
<itemDatas>
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false"/>
<itemData name="Keyword" defStyleNum="dsKeyword" spellChecking="false"/>
<itemData name="Function" defStyleNum="dsFunction" spellChecking="false"/>
<itemData name="Data Type" defStyleNum="dsDataType" spellChecking="false"/>
<itemData name="String" defStyleNum="dsString"/>
<itemData name="HereString" defStyleNum="dsVerbatimString"/>
<itemData name="Comment" defStyleNum="dsComment"/>
<itemData name="Cmdlets" defStyleNum="dsBuiltIn" spellChecking="false"/>
<itemData name="Symbol" defStyleNum="dsNormal" spellChecking="false"/>
<itemData name="Variable" defStyleNum="dsVariable" spellChecking="false"/>
<itemData name="Special Variable" defStyleNum="dsVariable" bold="1" spellChecking="false"/>
</itemDatas>
</highlighting>
<general>
<comments>
<comment name="singleLine" start="#" />
<comment name="multiLine" start="&lt;#" end="#&gt;" region="CommentRegion"/>
</comments>
<keywords casesensitive="0" weakDeliminator=":-"/>
</general>
</language>

View File

@@ -0,0 +1,688 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language>
<!-- Python syntax highlightning v0.9 by Per Wigren -->
<!-- Python syntax highlighting v1.9 by Michael Bueker (improved keyword differentiation) -->
<!-- Python syntax highlighting v1.97 by Paul Giannaros -->
<!-- Python syntax highlighting v1.99 by Primoz Anzur -->
<!-- Python syntax highlighting v2.01 by Paul Giannaros:
* full format character support
* unicode string modifier supported -->
<!-- v2.02 remove RegExpr for nums and make indent consistent -->
<!-- v2.03 highlight decorators, remove operator regex, don't highlight parens as operators -->
<!-- v2.04 make alerts visible even if they are directly after ''' or # without a space -->
<!-- v2.06 decorator names can (and often do) contain periods -->
<!-- v2.07 add support for %prog and co, see bug 142832 -->
<!-- v2.08 add missing overloaders, new Python 3 statements, builtins, and keywords -->
<!-- v2.29 recognize escape sequenzes correctly -->
<language name="Python" version="9" style="python" indenter="python" kateversion="5.0" section="Scripts" extensions="*.py;*.pyw;SConstruct;SConscript" mimetype="application/x-python;text/x-python;text/x-python3" casesensitive="1" author="Michael Bueker" license="">
<highlighting>
<list name="import">
<item>import</item>
<item>from</item>
<item>as</item>
</list>
<list name="defs">
<item>class</item>
<item>def</item>
<item>del</item>
<item>global</item>
<item>lambda</item>
<item>nonlocal</item>
</list>
<list name="operators">
<item>and</item>
<item>in</item>
<item>is</item>
<item>not</item>
<item>or</item>
</list>
<list name="flow">
<item>assert</item>
<item>break</item>
<item>continue</item>
<item>elif</item>
<item>else</item>
<item>except</item>
<item>finally</item>
<item>for</item>
<item>if</item>
<item>pass</item>
<item>raise</item>
<item>return</item>
<item>try</item>
<item>while</item>
<item>with</item>
<item>yield</item>
<item>async</item>
<item>await</item>
</list>
<list name="builtinfuncs">
<item>__import__</item>
<item>abs</item>
<item>all</item>
<item>any</item>
<item>apply</item>
<item>ascii</item>
<item>basestring</item>
<item>bin</item>
<item>bool</item>
<item>buffer</item>
<item>bytearray</item>
<item>bytes</item>
<item>callable</item>
<item>chr</item>
<item>classmethod</item>
<item>cmp</item>
<item>coerce</item>
<item>compile</item>
<item>complex</item>
<item>delattr</item>
<item>dict</item>
<item>dir</item>
<item>divmod</item>
<item>enumerate</item>
<item>eval</item>
<item>exec</item>
<item>execfile</item>
<item>file</item>
<item>filter</item>
<item>float</item>
<item>format</item>
<item>frozenset</item>
<item>getattr</item>
<item>globals</item>
<item>hasattr</item>
<item>hash</item>
<item>help</item>
<item>hex</item>
<item>id</item>
<item>input</item>
<item>int</item>
<item>intern</item>
<item>isinstance</item>
<item>issubclass</item>
<item>iter</item>
<item>len</item>
<item>list</item>
<item>locals</item>
<item>long</item>
<item>map</item>
<item>max</item>
<item>memoryview</item>
<item>min</item>
<item>next</item>
<item>object</item>
<item>oct</item>
<item>open</item>
<item>ord</item>
<item>pow</item>
<item>print</item>
<item>property</item>
<item>range</item>
<item>raw_input</item>
<item>reduce</item>
<item>reload</item>
<item>repr</item>
<item>reversed</item>
<item>round</item>
<item>set</item>
<item>setattr</item>
<item>slice</item>
<item>sorted</item>
<item>staticmethod</item>
<item>str</item>
<item>sum</item>
<item>super</item>
<item>tuple</item>
<item>type</item>
<item>unichr</item>
<item>unicode</item>
<item>vars</item>
<item>xrange</item>
<item>zip</item>
</list>
<list name="specialvars">
<item>None</item>
<item>self</item>
<item>True</item>
<item>False</item>
<item>NotImplemented</item>
<item>Ellipsis</item>
<item>__debug__</item>
<item>__file__</item>
<item>__name__</item>
</list>
<list name="bindings">
<item>SIGNAL</item>
<item>SLOT</item>
<item>connect</item>
</list>
<list name="overloaders">
<item>__new__</item>
<item>__init__</item>
<item>__del__</item>
<item>__repr__</item>
<item>__str__</item>
<item>__lt__</item>
<item>__le__</item>
<item>__eq__</item>
<item>__ne__</item>
<item>__gt__</item>
<item>__ge__</item>
<item>__cmp__</item>
<item>__rcmp__</item>
<item>__hash__</item>
<item>__nonzero__</item>
<item>__unicode__</item>
<item>__getattr__</item>
<item>__setattr__</item>
<item>__delattr__</item>
<item>__getattribute__</item>
<item>__get__</item>
<item>__set__</item>
<item>__delete__</item>
<item>__call__</item>
<item>__len__</item>
<item>__getitem__</item>
<item>__setitem__</item>
<item>__delitem__</item>
<item>__iter__</item>
<item>__reversed__</item>
<item>__contains__</item>
<item>__getslice__</item>
<item>__setslice__</item>
<item>__delslice__</item>
<item>__add__</item>
<item>__sub__</item>
<item>__mul__</item>
<item>__floordiv__</item>
<item>__mod__</item>
<item>__divmod__</item>
<item>__pow__</item>
<item>__lshift__</item>
<item>__rshift__</item>
<item>__and__</item>
<item>__xor__</item>
<item>__or__</item>
<item>__div__</item>
<item>__truediv__</item>
<item>__radd__</item>
<item>__rsub__</item>
<item>__rmul__</item>
<item>__rdiv__</item>
<item>__rtruediv__</item>
<item>__rfloordiv__</item>
<item>__rmod__</item>
<item>__rdivmod__</item>
<item>__rpow__</item>
<item>__rlshift__</item>
<item>__rrshift__</item>
<item>__rand__</item>
<item>__rxor__</item>
<item>__ror__</item>
<item>__iadd__</item>
<item>__isub__</item>
<item>__imul__</item>
<item>__idiv__</item>
<item>__itruediv__</item>
<item>__ifloordiv__</item>
<item>__imod__</item>
<item>__ipow__</item>
<item>__ilshift__</item>
<item>__irshift__</item>
<item>__iand__</item>
<item>__ixor__</item>
<item>__ior__</item>
<item>__neg__</item>
<item>__pos__</item>
<item>__abs__</item>
<item>__invert__</item>
<item>__complex__</item>
<item>__int__</item>
<item>__long__</item>
<item>__float__</item>
<item>__oct__</item>
<item>__hex__</item>
<item>__index__</item>
<item>__coerce__</item>
<item>__enter__</item>
<item>__exit__</item>
<item>__bytes__</item>
<item>__format__</item>
<item>__next__</item>
<item>__dir__</item>
<item>__await__</item>
<item>__aiter__</item>
<item>__anext__</item>
<item>__aenter__</item>
<item>__aexit__</item>
</list>
<list name="exceptions">
<!--
Exceptions list resources used:
- http://docs.python.org/2.7/library/exceptions.html#exception-hierarchy
- http://docs.python.org/3.4/library/exceptions.html#exception-hierarchy
-->
<item>ArithmeticError</item>
<item>AssertionError</item>
<item>AttributeError</item>
<item>BaseException</item>
<item>BlockingIOError</item>
<item>BrokenPipeError</item>
<item>BufferError</item>
<item>BytesWarning</item>
<item>ChildProcessError</item>
<item>ConnectionAbortedError</item>
<item>ConnectionError</item>
<item>ConnectionRefusedError</item>
<item>ConnectionResetError</item>
<item>DeprecationWarning</item>
<item>EnvironmentError</item>
<item>EOFError</item>
<item>Exception</item>
<item>FileExistsError</item>
<item>FileNotFoundError</item>
<item>FloatingPointError</item>
<item>FutureWarning</item>
<item>GeneratorExit</item>
<item>ImportError</item>
<item>ImportWarning</item>
<item>IndentationError</item>
<item>IndexError</item>
<item>InterruptedError</item>
<item>IOError</item>
<item>IsADirectoryError</item>
<item>KeyboardInterrupt</item>
<item>KeyError</item>
<item>LookupError</item>
<item>MemoryError</item>
<item>NameError</item>
<item>NotADirectoryError</item>
<item>NotImplementedError</item>
<item>OSError</item>
<item>OverflowError</item>
<item>PendingDeprecationWarning</item>
<item>PermissionError</item>
<item>ProcessLookupError</item>
<item>ReferenceError</item>
<item>ResourceWarning</item>
<item>RuntimeError</item>
<item>RuntimeWarning</item>
<item>StandardError</item>
<item>StopIteration</item>
<item>SyntaxError</item>
<item>SyntaxWarning</item>
<item>SystemError</item>
<item>SystemExit</item>
<item>TabError</item>
<item>TimeoutError</item>
<item>TypeError</item>
<item>UnboundLocalError</item>
<item>UnicodeDecodeError</item>
<item>UnicodeEncodeError</item>
<item>UnicodeError</item>
<item>UnicodeTranslateError</item>
<item>UnicodeWarning</item>
<item>UserWarning</item>
<item>ValueError</item>
<item>Warning</item>
<item>WindowsError</item>
<item>ZeroDivisionError</item>
</list>
<contexts>
<context name="Normal" attribute="Normal Text" lineEndContext="#stay">
<keyword attribute="Import" String="import" context="#stay"/>
<keyword attribute="Definition Keyword" String="defs" context="#stay"/>
<keyword attribute="Operator Keyword" String="operators" context="#stay"/>
<keyword attribute="Flow Control Keyword" String="flow" context="#stay"/>
<keyword attribute="Builtin Function" String="builtinfuncs" context="#stay"/>
<keyword attribute="Special Variable" String="specialvars" context="#stay"/>
<keyword attribute="Extensions" String="bindings" context="#stay"/>
<keyword attribute="Exceptions" String="exceptions" context="#stay"/>
<keyword attribute="Overloaders" String="overloaders" context="#stay"/>
<RegExpr attribute="Normal Text" String="[a-zA-Z_][a-zA-Z_0-9]{2,}" context="#stay"/>
<RegExpr attribute="Complex" String=" ((([0-9]*\.[0-9]+|[0-9]+\.)|([0-9]+|([0-9]*\.[0-9]+|[0-9]+\.))[eE](\+|-)?[0-9]+)|[0-9]+)[jJ]" context="#stay"/>
<Float attribute="Float" context="#stay" />
<HlCHex attribute="Hex" context="#stay"/>
<HlCOct attribute="Octal" context="#stay"/>
<Int attribute="Int" context="Int Suffixes"/>
<RegExpr attribute="Int" String=" ([0-9]+_)+[0-9]+" context="#stay"/>
<RegExpr attribute="Float" String=" ([0-9]+_)+[0-9]+\.[0-9]+" context="#stay"/>
<RegExpr attribute="Hex" String=" [0-9]x([A-F0-9]+_)+[A-F0-9]+" context="#stay"/>
<DetectChar attribute="Normal Text" char="{" context="Dictionary" beginRegion="Dictionary"/>
<DetectChar attribute="Normal Text" char="[" context="List" beginRegion="List"/>
<DetectChar attribute="Normal Text" char="(" context="Tuple" beginRegion="Tuple"/>
<IncludeRules context="CommentVariants" />
<DetectChar attribute="Comment" char="#" context="Hash comment"/>
<IncludeRules context="StringVariants" />
<RegExpr attribute="Decorator" String="@[_a-zA-Z][\._a-zA-Z0-9]*" firstNonSpace="true"/>
<AnyChar attribute="Operator" String="+*/%\|=;\!&lt;&gt;!^&amp;~-@" context="#stay"/>
</context>
<context name="Int Suffixes" attribute="Int" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<StringDetect attribute="Int" context="#pop" String="L" insensitive="true"/>
</context>
<context name="#CheckForString" attribute="Normal Text" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectSpaces/>
<LineContinue attribute="Normal Text" context="CheckForStringNext"/>
</context>
<context name="CheckForStringNext" attribute="Normal Text" lineEndContext="#pop" fallthrough="true" fallthroughContext="#pop">
<DetectSpaces/>
<LineContinue attribute="Normal Text" context="CheckForStringNext"/>
<IncludeRules context="StringVariants"/>
</context>
<context name="StringVariants" attribute="Normal Text" lineEndContext="#stay">
<DetectSpaces/>
<RegExpr attribute="String" String="u?'''" insensitive="true" context="Triple A-string" beginRegion="Triple A-region"/>
<RegExpr attribute="String" String="u?&quot;&quot;&quot;" insensitive="true" context="Triple Q-string" beginRegion="Triple Q-region"/>
<RegExpr attribute="String" String="u?'" insensitive="true" context="Single A-string"/>
<RegExpr attribute="String" String="u?&quot;" insensitive="true" context="Single Q-string"/>
<RegExpr attribute="Raw String" String="(u?r|ru)'''" insensitive="true" context="Raw Triple A-string" beginRegion="Triple A-region"/>
<RegExpr attribute="Raw String" String="(u?r|ru)&quot;&quot;&quot;" insensitive="true" context="Raw Triple Q-string" beginRegion="Triple Q-region"/>
<RegExpr attribute="Raw String" String="(u?r|ru)'" insensitive="true" context="Raw A-string"/>
<RegExpr attribute="Raw String" String="(u?r|ru)&quot;" insensitive="true" context="Raw Q-string"/>
<StringDetect attribute="F-String" String="f'''" insensitive="true" context="Triple A-F-String" beginRegion="Triple A-region"/>
<StringDetect attribute="F-String" String="f&quot;&quot;&quot;" insensitive="true" context="Triple Q-F-String" beginRegion="Triple Q-region"/>
<StringDetect attribute="F-String" String="f'" insensitive="true" context="Single A-F-String"/>
<StringDetect attribute="F-String" String="f&quot;" insensitive="true" context="Single Q-F-String"/>
<RegExpr attribute="Raw F-String" String="(fr|rf)'''" insensitive="true" context="Raw Triple A-F-String" beginRegion="Triple A-region"/>
<RegExpr attribute="Raw F-String" String="(fr|rf)&quot;&quot;&quot;" insensitive="true" context="Raw Triple Q-F-String" beginRegion="Triple Q-region"/>
<RegExpr attribute="Raw F-String" String="(fr|rf)'" insensitive="true" context="Raw A-F-String"/>
<RegExpr attribute="Raw F-String" String="(fr|rf)&quot;" insensitive="true" context="Raw Q-F-String"/>
</context>
<context name="CommentVariants" attribute="Normal Text" lineEndContext="#stay">
<DetectSpaces/>
<RegExpr attribute="Comment" String="u?'''" insensitive="true" firstNonSpace="true" context="Triple A-comment" beginRegion="Triple A-region"/>
<RegExpr attribute="Comment" String="u?&quot;&quot;&quot;" insensitive="true" firstNonSpace="true" context="Triple Q-comment" beginRegion="Triple Q-region"/>
<RegExpr attribute="Comment" String="u?'" insensitive="true" firstNonSpace="true" context="Single A-comment"/>
<RegExpr attribute="Comment" String="u?&quot;" insensitive="true" firstNonSpace="true" context="Single Q-comment"/>
<RegExpr attribute="Comment" String="(u?r|ru)'''" insensitive="true" firstNonSpace="true" context="Triple A-comment" beginRegion="Triple A-region"/>
<RegExpr attribute="Comment" String="(u?r|ru)&quot;&quot;&quot;" insensitive="true" firstNonSpace="true" context="Triple Q-comment" beginRegion="Triple Q-region"/>
<RegExpr attribute="Comment" String="(u?r|ru)'" insensitive="true" firstNonSpace="true" context="Single A-comment"/>
<RegExpr attribute="Comment" String="(u?r|ru)&quot;" insensitive="true" firstNonSpace="true" context="Single Q-comment"/>
</context>
<context name="Dictionary" attribute="Normal Text" lineEndContext="#stay" noIndentationBasedFolding="true">
<DetectSpaces/>
<DetectChar attribute="Normal Text" char="}" context="#pop" endRegion="Dictionary"/>
<IncludeRules context="StringVariants" />
<IncludeRules context="Normal" />
</context>
<context name="List" attribute="Normal Text" lineEndContext="#stay" noIndentationBasedFolding="true">
<DetectSpaces/>
<DetectChar attribute="Normal Text" char="]" context="#pop" endRegion="List"/>
<IncludeRules context="StringVariants" />
<IncludeRules context="Normal" />
</context>
<context name="Tuple" attribute="Normal Text" lineEndContext="#stay" noIndentationBasedFolding="true">
<DetectSpaces/>
<DetectChar attribute="Normal Text" char=")" context="#pop" endRegion="Tuple"/>
<IncludeRules context="StringVariants" />
<IncludeRules context="Normal" />
</context>
<!-- Comments -->
<context name="Hash comment" attribute="Comment" lineEndContext="#pop">
<IncludeRules context="##Alerts" />
<IncludeRules context="##Modelines" />
</context>
<context name="Triple A-comment" attribute="Comment" lineEndContext="#stay" noIndentationBasedFolding="true">
<IncludeRules context="stringescape"/>
<StringDetect attribute="Comment" String="'''" context="#pop" endRegion="Triple A-region"/>
<IncludeRules context="##Alerts" />
</context>
<context name="Triple Q-comment" attribute="Comment" lineEndContext="#stay" noIndentationBasedFolding="true">
<IncludeRules context="stringescape"/>
<StringDetect attribute="Comment" String="&quot;&quot;&quot;" context="#pop" endRegion="Triple Q-region"/>
<IncludeRules context="##Alerts" />
</context>
<context name="Single A-comment" attribute="Comment" lineEndContext="#stay">
<IncludeRules context="stringescape"/>
<DetectChar attribute="Comment" char="'" context="#pop"/>
<IncludeRules context="##Alerts" />
</context>
<context name="Single Q-comment" attribute="Comment" lineEndContext="#stay">
<IncludeRules context="stringescape"/>
<DetectChar attribute="Comment" char="&quot;" context="#pop"/>
<IncludeRules context="##Alerts" />
</context>
<!-- Strings -->
<!-- format characters -->
<context name="stringformat" attribute="String Substitution" lineEndContext="#stay">
<!-- Python 2 style. Syntax:
1. start character '%'
2. [optional] Mapping key, e.g. '(foo)'
3. [optional] Conversion flags, one of '#0- +'
4. [optional] Minimum width, integer or '*'
5. [optional] Precision, '.' followed by integer or '*'
6. [optional] Length modifier, one of 'hlL'
7. conversion type, one of 'crsdiouxXeEfFgG%'
[Special cases: %prog and %default - see http://docs.python.org/library/optparse.html]
-->
<RegExpr attribute="String Substitution" String="%((\([a-zA-Z0-9_]+\))?[#0\- +]?([1-9][0-9]*|\*)?(\.([1-9][0-9]*|\*))?[hlL]?[crsdiouxXeEfFgG%]|prog|default)" context="#stay"/>
<!-- http://docs.python.org/2/library/string.html#format-string-syntax:
replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name ::= arg_name ("." attribute_name | "[" element_index "]")*
arg_name ::= [identifier | integer]
attribute_name ::= identifier
element_index ::= integer | index_string
index_string ::= <any source character except "]"> +
conversion ::= "r" | "s"
format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
fill ::= <any character>
align ::= "<" | ">" | "=" | "^"
sign ::= "+" | "-" | " "
width ::= integer
precision ::= integer
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"
-->
<RegExpr attribute="String Substitution" String="\{(([a-zA-Z0-9_]+|[0-9]+)(\.[a-zA-Z0-9_]+|\[[^ \]]+\])*)?(![rs])?(:([^}]?[&lt;&gt;=^])?[ +-]?#?0?[0-9]*(\.[0-9]+)?[bcdeEfFgGnosxX%]?)?\}" context="#stay"/>
<Detect2Chars attribute="String Substitution" char="{" char1="{" context="#stay" />
<Detect2Chars attribute="String Substitution" char="}" char1="}" context="#stay" />
</context>
<!-- escape characters -->
<context name="stringescape" attribute="String Char" lineEndContext="#stay">
<!-- As this highlighting style is for both, Python 2 and 3,
we do not know if a normal string is “unicode” or not. So we
-->
<RegExpr attribute="String Char" String="\\[\\'&quot;abfnrtv]" context="#stay"/>
<RegExpr attribute="String Char" String="\\[0-7]{1,3}" context="#stay"/>
<RegExpr attribute="String Char" String="\\x[0-9A-Fa-f]{2}" context="#stay"/>
<RegExpr attribute="String Char" String="\\u[0-9A-Fa-f]{4}" context="#stay"/>
<RegExpr attribute="String Char" String="\\U[0-9A-Fa-f]{8}" context="#stay"/>
<RegExpr attribute="String Char" String="\\N\{[a-zA-Z0-9\- ]+\}" context="#stay"/>
</context>
<!-- f-literals -->
<context name="stringinterpolation" attribute="F-String" lineEndContext="#stay">
<Detect2Chars attribute="String Char" char="{" char1="{" context="#stay"/>
<DetectChar attribute="String Substitution" char="{" context="String Interpolation"/>
</context>
<context name="String Interpolation" attribute="String Substitution" lineEndContext="#stay">
<DetectChar attribute="Error" char="\" context="#pop"/>
<RegExpr attribute="String Substitution" String="(![rs])?(:([^}]?[&lt;&gt;=^])?[ +-]?#?0?[0-9]*(\.[0-9]+)?[bcdeEfFgGnosxX%]?)?\}" context="#pop"/>
<IncludeRules context="Normal"/> <!-- TODO: create expression context instead -->
</context>
<!--
It follows a Binary tree of string kinds (not even touching byte literals).
The levels are:
1. triple- vs. single-quoted
2. apostrophe vs. quotation mark
3. static vs. interpolated (f-literal)
4. escaped vs. raw
Adding byte literals wouldnt make the current 2⁴ into 2⁵ contexts, as there are no byte f-literals
-->
<!-- Triple-quoted A-strings -->
<context name="Triple A-string" attribute="String" lineEndContext="#stay" noIndentationBasedFolding="true">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringformat"/>
<StringDetect attribute="String" String="'''" context="#pop#CheckForString" endRegion="Triple A-region"/>
</context>
<context name="Raw Triple A-string" attribute="Raw String" lineEndContext="#stay" noIndentationBasedFolding="true">
<HlCStringChar attribute="Raw String" context="#stay"/>
<IncludeRules context="stringformat"/>
<StringDetect attribute="Raw String" String="'''" context="#pop#CheckForString" endRegion="Triple A-region"/>
</context>
<context name="Triple A-F-String" attribute="F-String" lineEndContext="#stay" noIndentationBasedFolding="true">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringinterpolation"/>
<StringDetect attribute="F-String" String="'''" context="#pop#CheckForString" endRegion="Triple A-region"/>
</context>
<context name="Raw Triple A-F-String" attribute="Raw F-String" lineEndContext="#stay" noIndentationBasedFolding="true">
<HlCStringChar attribute="Raw F-String" context="#stay"/>
<IncludeRules context="stringinterpolation"/>
<StringDetect attribute="Raw F-String" String="'''" context="#pop#CheckForString" endRegion="Triple A-region"/>
</context>
<!-- Triple-quoted Q-strings -->
<context name="Triple Q-string" attribute="String" lineEndContext="#stay" noIndentationBasedFolding="true">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringformat"/>
<StringDetect attribute="String" String="&quot;&quot;&quot;" context="#pop#CheckForString" endRegion="Triple Q-region"/>
</context>
<context name="Raw Triple Q-string" attribute="Raw String" lineEndContext="#stay" noIndentationBasedFolding="true">
<HlCStringChar attribute="Raw String" context="#stay"/>
<IncludeRules context="stringformat"/>
<StringDetect attribute="Raw String" String="&quot;&quot;&quot;" context="#pop#CheckForString" endRegion="Triple Q-region"/>
</context>
<context name="Triple Q-F-String" attribute="F-String" lineEndContext="#stay" noIndentationBasedFolding="true">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringinterpolation"/>
<StringDetect attribute="F-String" String="&quot;&quot;&quot;" context="#pop#CheckForString" endRegion="Triple Q-region"/>
</context>
<context name="Raw Triple Q-F-String" attribute="Raw F-String" lineEndContext="#stay" noIndentationBasedFolding="true">
<HlCStringChar attribute="Raw F-String" context="#stay"/>
<IncludeRules context="stringinterpolation"/>
<StringDetect attribute="Raw F-String" String="&quot;&quot;&quot;" context="#pop#CheckForString" endRegion="Triple Q-region"/>
</context>
<!-- Single-quoted A-strings -->
<context name="Single A-string" attribute="String" lineEndContext="#stay">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringformat"/>
<DetectChar attribute="String" char="'" context="#pop#CheckForString"/>
</context>
<context name="Raw A-string" attribute="Raw String" lineEndContext="#stay">
<HlCStringChar attribute="Raw String" context="#stay"/>
<IncludeRules context="stringformat"/>
<DetectChar attribute="Raw String" char="'" context="#pop#CheckForString"/>
</context>
<context name="Single A-F-String" attribute="F-String" lineEndContext="#stay">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringinterpolation"/>
<DetectChar attribute="F-String" char="'" context="#pop#CheckForString"/>
</context>
<context name="Raw A-F-String" attribute="Raw F-String" lineEndContext="#stay">
<HlCStringChar attribute="Raw F-String" context="#stay"/>
<IncludeRules context="stringinterpolation"/>
<DetectChar attribute="Raw F-String" char="'" context="#pop#CheckForString"/>
</context>
<!-- Single-quoted Q-strings -->
<context name="Single Q-string" attribute="String" lineEndContext="#stay">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringformat"/>
<DetectChar attribute="String" char="&quot;" context="#pop#CheckForString"/>
</context>
<context name="Raw Q-string" attribute="Raw String" lineEndContext="#stay">
<HlCStringChar attribute="Raw String" context="#stay"/>
<IncludeRules context="stringformat"/>
<DetectChar attribute="Raw String" char="&quot;" context="#pop#CheckForString"/>
</context>
<context name="Single Q-F-String" attribute="F-String" lineEndContext="#stay">
<IncludeRules context="stringescape"/>
<IncludeRules context="stringinterpolation"/>
<DetectChar attribute="F-String" char="&quot;" context="#pop#CheckForString"/>
</context>
<context name="Raw Q-F-String" attribute="Raw F-String" lineEndContext="#stay">
<HlCStringChar attribute="Raw F-String" context="#stay"/>
<IncludeRules context="stringinterpolation"/>
<DetectChar attribute="Raw F-String" char="&quot;" context="#pop#CheckForString"/>
</context>
</contexts>
<itemDatas>
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false"/>
<itemData name="Definition Keyword" defStyleNum="dsKeyword" spellChecking="false"/>
<itemData name="Operator" defStyleNum="dsOperator" spellChecking="false"/>
<itemData name="Operator Keyword" defStyleNum="dsKeyword" spellChecking="false"/>
<itemData name="Flow Control Keyword" defStyleNum="dsControlFlow" spellChecking="false"/>
<itemData name="Builtin Function" defStyleNum="dsBuiltIn" spellChecking="false"/>
<itemData name="Special Variable" defStyleNum="dsVariable" spellChecking="false"/>
<itemData name="Extensions" defStyleNum="dsExtension" spellChecking="false"/>
<itemData name="Exceptions" defStyleNum="dsPreprocessor" spellChecking="false"/>
<itemData name="Overloaders" defStyleNum="dsFunction" spellChecking="false"/>
<itemData name="Import" defStyleNum="dsImport" spellChecking="false"/>
<itemData name="Float" defStyleNum="dsFloat" spellChecking="false"/>
<itemData name="Int" defStyleNum="dsDecVal" spellChecking="false"/>
<itemData name="Hex" defStyleNum="dsBaseN" spellChecking="false"/>
<itemData name="Octal" defStyleNum="dsBaseN" spellChecking="false"/>
<itemData name="Complex" defStyleNum="dsOthers" spellChecking="false"/>
<itemData name="Comment" defStyleNum="dsComment"/>
<itemData name="String" defStyleNum="dsString"/>
<itemData name="Raw String" defStyleNum="dsVerbatimString"/>
<itemData name="F-String" defStyleNum="dsSpecialString"/>
<itemData name="Raw F-String" defStyleNum="dsVerbatimString"/>
<itemData name="String Char" defStyleNum="dsChar" spellChecking="false"/>
<itemData name="String Substitution" defStyleNum="dsSpecialChar" spellChecking="false"/>
<itemData name="Decorator" defStyleNum="dsAttribute" spellChecking="false"/>
<itemData name="Error" defStyleNum="dsError"/>
</itemDatas>
</highlighting>
<general>
<folding indentationsensitive="1" />
<emptyLines>
<emptyLine regexpr="(?:\s+|\s*#.*)"/>
</emptyLines>
<comments>
<comment name="singleLine" start="#" position="afterwhitespace"/>
</comments>
<keywords casesensitive="1" additionalDeliminator="#'"/>
</general>
</language>
<!-- kate: space-indent off; indent-width 4; -->

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "language.dtd">
<language name="QDoc Configuration"
version="1"
kateversion="5.0"
section="Configuration"
extensions="*.qdocconf"
author="Volker Krause (vkrause@kde.org)"
license="MIT">
<highlighting>
<list name="key-names">
<item>alias</item>
<item>buildversion</item>
<item>Cpp</item>
<item>customFilters</item>
<item>defines</item>
<item>depends</item>
<item>description</item>
<item>dita</item>
<item>edition</item>
<item>endheader</item>
<item>exampledirs</item>
<item>examples</item>
<item>excludedirs</item>
<item>excludefiles</item>
<item>falsehoods</item>
<item>file</item>
<item>filterAttributes</item>
<item>headerdirs</item>
<item>headers</item>
<item>HTML</item>
<item>imagedirs</item>
<item>images</item>
<item>indexes</item>
<item>indexRoot</item>
<item>indexTitle</item>
<item>language</item>
<item>macro</item>
<item>manifestmeta</item>
<item>name</item>
<item>namespace</item>
<item>navigation</item>
<item>outputdir</item>
<item>outputformats</item>
<item>outputprefixes</item>
<item>outputsuffixes</item>
<item>project</item>
<item>projects</item>
<item>qhp</item>
<item>selectors</item>
<item>sortPages</item>
<item>sourcedirs</item>
<item>sources</item>
<item>sources.fileextensions</item>
<item>spurious</item>
<item>subprojects</item>
<item>tabsize</item>
<item>tagfile</item>
<item>title</item>
<item>type</item>
<item>url</item>
<item>version</item>
<item>versionsym</item>
<item>virtualFolder</item>
</list>
<list name="function-names">
<item>include</item>
</list>
<list name="selector-names">
<item>namespace</item>
<item>class</item>
<item>qmltype</item>
<item>qmlclass</item>
<item>module</item>
<item>qmlmodule</item>
<item>doc</item>
<item>fake</item>
<item>group</item>
<item>example</item>
<item>headerfile</item>
<item>page</item>
<item>manual</item>
</list>
<contexts>
<context name="key-context" attribute="Normal Text" lineEndContext="#stay">
<DetectChar char="#" context="comment-context" column="0"/>
<keyword attribute="Keyword" String="key-names"/>
<keyword attribute="Function" String="function-names"/>
<DetectChar char="=" context="value-context"/>
<DetectChar char="(" context="argument-context"/>
</context>
<context name="value-context" attribute="Normal Text" lineEndContext="#pop" lineEmptyContext="#pop">
<DetectChar attribute="String" context="string-context" char="&quot;"/>
<keyword attribute="Selector" String="selector-names"/>
<RegExpr attribute="Variable" String="\$\w+"/>
<LineContinue char="\" context="#stay"/>
</context>
<context name="argument-context" attribute="Normal Text" lineEndContext="#stay">
<DetectChar attribute="String" context="string-context" char="&quot;"/>
<RegExpr attribute="Variable" String="\$\w+"/>
<DetectChar char=")" context="#pop"/>
<LineContinue char="\" context="#stay"/>
</context>
<context name="string-context" attribute="String" lineEndContext="#stay">
<HlCStringChar attribute="Special Character"/>
<RegExpr attribute="Variable" String="\$\w+"/>
<DetectChar attribute="String" context="#pop" char="&quot;"/>
</context>
<context name="comment-context" attribute="Comment" lineEndContext="#pop">
<IncludeRules context="##Alerts"/>
</context>
</contexts>
<itemDatas>
<itemData name="Normal Text" defStyleNum="dsNormal" spellChecking="false"/>
<itemData name="Keyword" defStyleNum="dsBuiltIn" spellChecking="false"/>
<itemData name="String" defStyleNum="dsString" spellChecking="false"/>
<itemData name="Special Character" defStyleNum="dsSpecialChar" spellChecking="false"/>
<itemData name="Variable" defStyleNum="dsVariable" spellChecking="false"/>
<itemData name="Comment" defStyleNum="dsComment"/>
<itemData name="Function" defStyleNum="dsFunction" spellChecking="false"/>
<itemData name="Selector" defStyleNum="dsExtension" spellChecking="false"/>
</itemDatas>
</highlighting>
<general>
<comments>
<comment name="singleLine" start="#"/>
</comments>
<keywords casesensitive="1" weakDeliminator="-/"/>
</general>
</language>

View File

@@ -0,0 +1,174 @@
{
"metadata" : {
"revision" : 2,
"name" : "Breeze Dark"
},
"text-styles": {
"Normal" : {
"text-color" : "#cfcfc2",
"selected-text-color" : "#cfcfc2",
"bold" : false,
"italic" : false,
"underline" : false,
"strike-through" : false
},
"Keyword" : {
"text-color" : "#cfcfc2",
"selected-text-color" : "#cfcfc2",
"bold" : true
},
"Function" : {
"text-color" : "#8e44ad",
"selected-text-color" : "#af81ff"
},
"Variable" : {
"text-color" : "#27aeae",
"selected-text-color" : "#27aeae"
},
"ControlFlow" : {
"text-color" : "#fdbc4b",
"selected-text-color" : "#fdbc4b",
"bold" : true
},
"Operator" : {
"text-color" : "#cfcfc2",
"selected-text-color" : "#cfcfc2"
},
"BuiltIn" : {
"text-color" : "#7f8c8d",
"selected-text-color" : "#bdc3c7"
},
"Extension" : {
"text-color" : "#0099ff",
"selected-text-color" : "#bdc3c7",
"bold" : true
},
"Preprocessor" : {
"text-color" : "#27ae60",
"selected-text-color" : "#27ae60"
},
"Attribute" : {
"text-color" : "#2980b9",
"selected-text-color" : "#fdbc4b"
},
"Char" : {
"text-color" : "#3daee9",
"selected-text-color" : "#3daee9"
},
"SpecialChar" : {
"text-color" : "#3daee9",
"selected-text-color" : "#3daee9"
},
"String" : {
"text-color" : "#f44f4f",
"selected-text-color" : "#f44f4f"
},
"VerbatimString" : {
"text-color" : "#da4453",
"selected-text-color" : "#da4453"
},
"SpecialString" : {
"text-color" : "#da4453",
"selected-text-color" : "#da4453"
},
"Import" : {
"text-color" : "#27ae60",
"selected-text-color" : "#27ae60"
},
"DataType" : {
"text-color" : "#2980b9",
"selected-text-color" : "#fdbc4b"
},
"DecVal" : {
"text-color" : "#f67400",
"selected-text-color" : "#f67400"
},
"BaseN" : {
"text-color" : "#f67400",
"selected-text-color" : "#f67400"
},
"Float" : {
"text-color" : "#f67400",
"selected-text-color" : "#f67400"
},
"Constant" : {
"text-color" : "#27aeae",
"selected-text-color" : "#27aeae",
"bold" : true
},
"Comment" : {
"text-color" : "#7a7c7d",
"selected-text-color" : "#808080"
},
"Documentation" : {
"text-color" : "#a43340",
"selected-text-color" : "#da4453"
},
"Annotation" : {
"text-color" : "#3f8058",
"selected-text-color" : "#54aa75"
},
"CommentVar" : {
"text-color" : "#7f8c8d",
"selected-text-color" : "#94a3a4"
},
"RegionMarker" : {
"text-color" : "#2980b9",
"selected-text-color" : "#3daee9",
"background-color" : "#153042"
},
"Information" : {
"text-color" : "#c45b00",
"selected-text-color" : "#e46700"
},
"Warning" : {
"text-color" : "#da4453",
"selected-text-color" : "#da4453"
},
"Alert" : {
"text-color" : "#95da4c",
"selected-text-color" : "#95da4c",
"background-color" : "#4d1f24",
"bold" : true
},
"Error" : {
"text-color" : "#da4453",
"selected-text-color" : "#da4453",
"underline" : true
},
"Others" : {
"text-color" : "#27ae60",
"selected-text-color" : "#27ae60"
}
},
"editor-colors": {
"background-color" : "#232629",
"code-folding" : "#224e65",
"bracket-matching" : "#8e44ad",
"current-line" : "#2A2E32",
"icon-border" : "#31363b",
"indentation-line" : "#3a3f44",
"line-numbers" : "#7a7c7d",
"current-line-number" : "#a5a6a8",
"mark-bookmark" : "#0404bf",
"mark-breakpoint-active" : "#8b0607",
"mark-breakpoint-reached" : "#6d6e07",
"mark-breakpoint-disabled" : "#820683",
"mark-execution" : "#4d4e50",
"mark-warning" : "#f67400",
"mark-error" : "#da4453",
"modified-lines" : "#c04900",
"replace-highlight" : "#808021",
"saved-lines" : "#1c8042",
"search-highlight" : "#218058",
"selection" : "#2d5c76",
"separator" : "#7a7c7d",
"spell-checking" : "#c0392b",
"tab-marker" : "#4d4d4d",
"template-background" : "#31363b",
"template-placeholder" : "#123723",
"template-focused-placeholder" : "#123723",
"template-read-only-placeholder" : "#4d1f24",
"word-wrap-marker" : "#3a3f44"
}
}

View File

@@ -0,0 +1,174 @@
{
"metadata" : {
"revision" : 3,
"name" : "Default"
},
"text-styles": {
"Normal" : {
"text-color" : "#1f1c1b",
"selected-text-color" : "#ffffff",
"bold" : false,
"italic" : false,
"underline" : false,
"strike-through" : false
},
"Keyword" : {
"text-color" : "#1f1c1b",
"selected-text-color" : "#ffffff",
"bold" : true
},
"Function" : {
"text-color" : "#644a9b",
"selected-text-color" : "#452886"
},
"Variable" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e"
},
"ControlFlow" : {
"text-color" : "#1f1c1b",
"selected-text-color" : "#ffffff",
"bold" : true
},
"Operator" : {
"text-color" : "#1f1c1b",
"selected-text-color" : "#ffffff"
},
"BuiltIn" : {
"text-color" : "#644a9b",
"selected-text-color" : "#452886",
"bold" : true
},
"Extension" : {
"text-color" : "#0095ff",
"selected-text-color" : "#ffffff",
"bold" : true
},
"Preprocessor" : {
"text-color" : "#006e28",
"selected-text-color" : "#006e28"
},
"Attribute" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e"
},
"Char" : {
"text-color" : "#924c9d",
"selected-text-color" : "#6c2477"
},
"SpecialChar" : {
"text-color" : "#3daee9",
"selected-text-color" : "#fcfcfc"
},
"String" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e"
},
"VerbatimString" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e"
},
"SpecialString" : {
"text-color" : "#ff5500",
"selected-text-color" : "#ff5500"
},
"Import" : {
"text-color" : "#ff5500",
"selected-text-color" : "#ff5500"
},
"DataType" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e"
},
"DecVal" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"BaseN" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"Float" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"Constant" : {
"text-color" : "#aa5500",
"selected-text-color" : "#5e2f00"
},
"Comment" : {
"text-color" : "#898887",
"selected-text-color" : "#5e5d5d"
},
"Documentation" : {
"text-color" : "#607880",
"selected-text-color" : "#46585e"
},
"Annotation" : {
"text-color" : "#ca60ca",
"selected-text-color" : "#a44ea4"
},
"CommentVar" : {
"text-color" : "#0095ff",
"selected-text-color" : "#ffffff"
},
"RegionMarker" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e",
"background-color" : "#e0e9f8"
},
"Information" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"Warning" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e"
},
"Alert" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e",
"background-color" : "#f7e6e6",
"bold" : true
},
"Error" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e",
"underline" : true
},
"Others" : {
"text-color" : "#006e28",
"selected-text-color" : "#006e28"
}
},
"editor-colors": {
"background-color" : "#ffffff",
"code-folding" : "#94caef",
"bracket-matching" : "#ffff00",
"current-line" : "#f8f7f6",
"icon-border" : "#f0f0f0",
"indentation-line" : "#d2d2d2",
"line-numbers" : "#a0a0a0",
"current-line-number" : "#1e1e1e",
"mark-bookmark" : "#0000ff",
"mark-breakpoint-active" : "#ff0000",
"mark-breakpoint-reached" : "#ffff00",
"mark-breakpoint-disabled" : "#ff00ff",
"mark-execution" : "#a0a0a4",
"mark-warning" : "#00ff00",
"mark-error" : "#ff0000",
"modified-lines" : "#fdbc4b",
"replace-highlight" : "#00ff00",
"saved-lines" : "#2ecc71",
"search-highlight" : "#ffff00",
"selection" : "#94caef",
"separator" : "#898887",
"spell-checking" : "#bf0303",
"tab-marker" : "#d2d2d2",
"template-background" : "#d6d2d0",
"template-placeholder" : "#baf8ce",
"template-focused-placeholder" : "#76da98",
"template-read-only-placeholder" : "#f6e6e6",
"word-wrap-marker" : "#ededed"
}
}

View File

@@ -0,0 +1,173 @@
{
"metadata" : {
"revision" : 3,
"name" : "Printing"
},
"text-styles": {
"Normal" : {
"text-color" : "#000000",
"selected-text-color" : "#ffffff",
"bold" : false,
"italic" : false,
"underline" : false,
"strike-through" : false
},
"Keyword" : {
"text-color" : "#000000",
"selected-text-color" : "#ffffff",
"bold" : true
},
"Function" : {
"text-color" : "#644a9b",
"selected-text-color" : "#452886"
},
"Variable" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e"
},
"ControlFlow" : {
"text-color" : "#000000",
"selected-text-color" : "#ffffff",
"bold" : true
},
"Operator" : {
"text-color" : "#000000",
"selected-text-color" : "#ffffff"
},
"BuiltIn" : {
"text-color" : "#644a9b",
"selected-text-color" : "#452886"
},
"Extension" : {
"text-color" : "#0095ff",
"selected-text-color" : "#ffffff",
"bold" : true
},
"Preprocessor" : {
"text-color" : "#006e28",
"selected-text-color" : "#006e28"
},
"Attribute" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e"
},
"Char" : {
"text-color" : "#924c9d",
"selected-text-color" : "#6c2477"
},
"SpecialChar" : {
"text-color" : "#ff5500",
"selected-text-color" : "#ff5500"
},
"String" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e"
},
"VerbatimString" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e"
},
"SpecialString" : {
"text-color" : "#ff5500",
"selected-text-color" : "#ff5500"
},
"Import" : {
"text-color" : "#644a9b",
"selected-text-color" : "#452886"
},
"DataType" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e"
},
"DecVal" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"BaseN" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"Float" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"Constant" : {
"text-color" : "#aa5500",
"selected-text-color" : "#5e2f00"
},
"Comment" : {
"text-color" : "#898887",
"selected-text-color" : "#5e5d5d"
},
"Documentation" : {
"text-color" : "#607880",
"selected-text-color" : "#46585e"
},
"Annotation" : {
"text-color" : "#ca60ca",
"selected-text-color" : "#a44ea4"
},
"CommentVar" : {
"text-color" : "#0095ff",
"selected-text-color" : "#ffffff"
},
"RegionMarker" : {
"text-color" : "#0057ae",
"selected-text-color" : "#00316e",
"background-color" : "#e0e9f8"
},
"Information" : {
"text-color" : "#b08000",
"selected-text-color" : "#805c00"
},
"Warning" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e"
},
"Alert" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e",
"background-color" : "#f7e6e6",
"bold" : true
},
"Error" : {
"text-color" : "#bf0303",
"selected-text-color" : "#9c0e0e",
"underline" : true
},
"Others" : {
"text-color" : "#006e28",
"selected-text-color" : "#006e28"
}
},
"editor-colors": {
"background-color" : "#ffffff",
"code-folding" : "#94caef",
"bracket-matching" : "#edf9ff",
"current-line" : "#f8f7f6",
"icon-border" : "#d6d2d0",
"indentation-line" : "#d2d2d2",
"line-numbers" : "#221f1e",
"current-line-number" : "#221f1e",
"mark-bookmark" : "#0000ff",
"mark-breakpoint-active" : "#ff0000",
"mark-breakpoint-reached" : "#ffff00",
"mark-breakpoint-disabled" : "#ff00ff",
"mark-execution" : "#a0a0a4",
"mark-warning" : "#00ff00",
"mark-error" : "#ff0000",
"modified-lines" : "#f6e6e6",
"replace-highlight" : "#00ff00",
"saved-lines" : "#baf8ce",
"search-highlight" : "#ffff00",
"selection" : "#94caef",
"separator" : "#898887",
"spell-checking" : "#bf0303",
"tab-marker" : "#d2d2d2",
"template-background" : "#d6d2d0",
"template-placeholder" : "#baf8ce",
"template-focused-placeholder" : "#76da98",
"template-read-only-placeholder" : "#f6e6e6",
"word-wrap-marker" : "#ededed"
}
}

View File

@@ -0,0 +1,175 @@
{
"metadata" : {
"revision" : 1,
"name" : "Solarized Dark"
},
"text-styles": {
"Normal" : {
"text-color" : "#839496",
"selected-text-color" : "#586e75",
"bold" : false,
"italic" : false,
"underline" : false,
"strike-through" : false
},
"Keyword" : {
"text-color" : "#859900",
"selected-text-color" : "#859900",
"bold" : true
},
"Function" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"Variable" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"ControlFlow" : {
"text-color" : "#859900",
"selected-text-color" : "#859900",
"bold" : true
},
"Operator" : {
"text-color" : "#859900",
"selected-text-color" : "#859900"
},
"BuiltIn" : {
"text-color" : "#cb4b16",
"selected-text-color" : "#cb4b16"
},
"Extension" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2",
"bold" : true
},
"Preprocessor" : {
"text-color" : "#cb4b16",
"selected-text-color" : "#cb4b16"
},
"Attribute" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"Char" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"SpecialChar" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f"
},
"String" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"VerbatimString" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"SpecialString" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f"
},
"Import" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"DataType" : {
"text-color" : "#b58900",
"selected-text-color" : "#b58900",
"bold" : true
},
"DecVal" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"BaseN" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"Float" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"Constant" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198",
"bold" : true
},
"Comment" : {
"text-color" : "#586e75",
"selected-text-color" : "#93a1a1",
"italic" : true
},
"Documentation" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f"
},
"Annotation" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"CommentVar" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"RegionMarker" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2",
"background-color" : "#073642"
},
"Information" : {
"text-color" : "#b58900",
"selected-text-color" : "#b58900"
},
"Warning" : {
"text-color" : "#cb4b16",
"selected-text-color" : "#cb4b16"
},
"Alert" : {
"text-color" : "#d33682",
"selected-text-color" : "#d33682",
"bold" : true
},
"Error" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f",
"underline" : true
},
"Others" : {
"text-color" : "#859900",
"selected-text-color" : "#859900"
}
},
"editor-colors": {
"background-color" : "#002b36",
"code-folding" : "#6c71c4",
"bracket-matching" : "#073642",
"current-line" : "#073642",
"icon-border" : "#073642",
"indentation-line" : "#073642",
"line-numbers" : "#586e75",
"current-line-number" : "#586e75",
"mark-bookmark" : "#268bd2",
"mark-breakpoint-active" : "#dc322f",
"mark-breakpoint-reached" : "#b58900",
"mark-breakpoint-disabled" : "#d33682",
"mark-execution" : "#586e75",
"mark-warning" : "#cb4b16",
"mark-error" : "#dc322f",
"modified-lines" : "#cb4b16",
"replace-highlight" : "#859900",
"saved-lines" : "#2aa198",
"search-highlight" : "#b58900",
"selection" : "#eee8d5",
"separator" : "#586e75",
"spell-checking" : "#dc322f",
"tab-marker" : "#586e75",
"template-background" : "#073642",
"template-placeholder" : "#073642",
"template-focused-placeholder" : "#073642",
"template-read-only-placeholder" : "#073642",
"word-wrap-marker" : "#586e75"
}
}

View File

@@ -0,0 +1,175 @@
{
"metadata" : {
"revision" : 1,
"name" : "Solarized Light"
},
"text-styles": {
"Normal" : {
"text-color" : "#657b83",
"selected-text-color" : "#839496",
"bold" : false,
"italic" : false,
"underline" : false,
"strike-through" : false
},
"Keyword" : {
"text-color" : "#859900",
"selected-text-color" : "#859900",
"bold" : true
},
"Function" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"Variable" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"ControlFlow" : {
"text-color" : "#859900",
"selected-text-color" : "#859900",
"bold" : true
},
"Operator" : {
"text-color" : "#859900",
"selected-text-color" : "#859900"
},
"BuiltIn" : {
"text-color" : "#cb4b16",
"selected-text-color" : "#cb4b16"
},
"Extension" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2",
"bold" : true
},
"Preprocessor" : {
"text-color" : "#cb4b16",
"selected-text-color" : "#cb4b16"
},
"Attribute" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"Char" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"SpecialChar" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f"
},
"String" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"VerbatimString" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"SpecialString" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f"
},
"Import" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"DataType" : {
"text-color" : "#b58900",
"selected-text-color" : "#b58900",
"bold" : true
},
"DecVal" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"BaseN" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"Float" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"Constant" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198",
"bold" : true
},
"Comment" : {
"text-color" : "#93a1a1",
"selected-text-color" : "#586e75",
"italic" : true
},
"Documentation" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f"
},
"Annotation" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2"
},
"CommentVar" : {
"text-color" : "#2aa198",
"selected-text-color" : "#2aa198"
},
"RegionMarker" : {
"text-color" : "#268bd2",
"selected-text-color" : "#268bd2",
"background-color" : "#eee8d5"
},
"Information" : {
"text-color" : "#b58900",
"selected-text-color" : "#b58900"
},
"Warning" : {
"text-color" : "#cb4b16",
"selected-text-color" : "#cb4b16"
},
"Alert" : {
"text-color" : "#d33682",
"selected-text-color" : "#d33682",
"bold" : true
},
"Error" : {
"text-color" : "#dc322f",
"selected-text-color" : "#dc322f",
"underline" : true
},
"Others" : {
"text-color" : "#859900",
"selected-text-color" : "#859900"
}
},
"editor-colors": {
"background-color" : "#fdf6e3",
"code-folding" : "#6c71c4",
"bracket-matching" : "#eee8d5",
"current-line" : "#eee8d5",
"icon-border" : "#eee8d5",
"indentation-line" : "#eee8d5",
"line-numbers" : "#93a1a1",
"current-line-number" : "#93a1a1",
"mark-bookmark" : "#268bd2",
"mark-breakpoint-active" : "#dc322f",
"mark-breakpoint-reached" : "#b58900",
"mark-breakpoint-disabled" : "#d33682",
"mark-execution" : "#93a1a1",
"mark-warning" : "#cb4b16",
"mark-error" : "#dc322f",
"modified-lines" : "#cb4b16",
"replace-highlight" : "#859900",
"saved-lines" : "#2aa198",
"search-highlight" : "#b58900",
"selection" : "#073642",
"separator" : "#93a1a1",
"spell-checking" : "#dc322f",
"tab-marker" : "#93a1a1",
"template-background" : "#eee8d5",
"template-placeholder" : "#eee8d5",
"template-focused-placeholder" : "#eee8d5",
"template-read-only-placeholder" : "#eee8d5",
"word-wrap-marker" : "#93a1a1"
}
}

View File

@@ -0,0 +1,10 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/org.kde.syntax-highlighting/themes">
<file alias="default.theme">default.theme</file>
<file alias="breeze-dark.theme">breeze-dark.theme</file>
<file alias="printing.theme">printing.theme</file>
<file alias="solarized-dark.theme">solarized-dark.theme</file>
<file alias="solarized-light.theme">solarized-light.theme</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,4 @@
if(Qt5Widgets_FOUND)
add_executable(codeeditor codeeditor.cpp main.cpp)
target_link_libraries(codeeditor Qt5::Widgets KF5SyntaxHighlighting)
endif()

View File

@@ -0,0 +1,358 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "codeeditor.h"
#include <definition.h>
#include <foldingregion.h>
#include <syntaxhighlighter.h>
#include <theme.h>
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QFontDatabase>
#include <QMenu>
#include <QPainter>
#include <QPalette>
class CodeEditorSidebar : public QWidget
{
Q_OBJECT
public:
explicit CodeEditorSidebar(CodeEditor *editor);
QSize sizeHint() const Q_DECL_OVERRIDE;
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
private:
CodeEditor *m_codeEditor;
};
CodeEditorSidebar::CodeEditorSidebar(CodeEditor *editor) :
QWidget(editor),
m_codeEditor(editor)
{
}
QSize CodeEditorSidebar::sizeHint() const
{
return QSize(m_codeEditor->sidebarWidth(), 0);
}
void CodeEditorSidebar::paintEvent(QPaintEvent *event)
{
m_codeEditor->sidebarPaintEvent(event);
}
void CodeEditorSidebar::mouseReleaseEvent(QMouseEvent *event)
{
if (event->x() >= width() - m_codeEditor->fontMetrics().lineSpacing()) {
auto block = m_codeEditor->blockAtPosition(event->y());
if (!block.isValid() || !m_codeEditor->isFoldable(block))
return;
m_codeEditor->toggleFold(block);
}
QWidget::mouseReleaseEvent(event);
}
CodeEditor::CodeEditor(QWidget *parent) :
QPlainTextEdit(parent),
m_highlighter(new KSyntaxHighlighting::SyntaxHighlighter(document())),
m_sideBar(new CodeEditorSidebar(this))
{
setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
setTheme((palette().color(QPalette::Base).lightness() < 128)
? m_repository.defaultTheme(KSyntaxHighlighting::Repository::DarkTheme)
: m_repository.defaultTheme(KSyntaxHighlighting::Repository::LightTheme));
connect(this, &QPlainTextEdit::blockCountChanged, this, &CodeEditor::updateSidebarGeometry);
connect(this, &QPlainTextEdit::updateRequest, this, &CodeEditor::updateSidebarArea);
connect(this, &QPlainTextEdit::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine);
updateSidebarGeometry();
highlightCurrentLine();
}
CodeEditor::~CodeEditor()
{
}
void CodeEditor::openFile(const QString& fileName)
{
QFile f(fileName);
if (!f.open(QFile::ReadOnly)) {
qWarning() << "Failed to open" << fileName << ":" << f.errorString();
return;
}
clear();
const auto def = m_repository.definitionForFileName(fileName);
m_highlighter->setDefinition(def);
setWindowTitle(fileName);
setPlainText(QString::fromUtf8(f.readAll()));
}
void CodeEditor::contextMenuEvent(QContextMenuEvent *event)
{
auto menu = createStandardContextMenu(event->pos());
menu->addSeparator();
auto openAction = menu->addAction(QStringLiteral("Open File..."));
connect(openAction, &QAction::triggered, this, [this]() {
const auto fileName = QFileDialog::getOpenFileName(this, QStringLiteral("Open File"));
if (!fileName.isEmpty())
openFile(fileName);
});
// syntax selection
auto hlActionGroup = new QActionGroup(menu);
hlActionGroup->setExclusive(true);
auto hlGroupMenu = menu->addMenu(QStringLiteral("Syntax"));
QMenu *hlSubMenu = hlGroupMenu;
QString currentGroup;
foreach (const auto &def, m_repository.definitions()) {
if (def.isHidden())
continue;
if (currentGroup != def.section()) {
currentGroup = def.section();
hlSubMenu = hlGroupMenu->addMenu(def.translatedSection());
}
Q_ASSERT(hlSubMenu);
auto action = hlSubMenu->addAction(def.translatedName());
action->setCheckable(true);
action->setData(def.name());
hlActionGroup->addAction(action);
if (def.name() == m_highlighter->definition().name())
action->setChecked(true);
}
connect(hlActionGroup, &QActionGroup::triggered, this, [this](QAction *action) {
const auto defName = action->data().toString();
const auto def = m_repository.definitionForName(defName);
m_highlighter->setDefinition(def);
});
// theme selection
auto themeGroup = new QActionGroup(menu);
themeGroup->setExclusive(true);
auto themeMenu = menu->addMenu(QStringLiteral("Theme"));
foreach (const auto &theme, m_repository.themes()) {
auto action = themeMenu->addAction(theme.translatedName());
action->setCheckable(true);
action->setData(theme.name());
themeGroup->addAction(action);
if (theme.name() == m_highlighter->theme().name())
action->setChecked(true);
}
connect(themeGroup, &QActionGroup::triggered, this, [this](QAction *action) {
const auto themeName = action->data().toString();
const auto theme = m_repository.theme(themeName);
setTheme(theme);
});
menu->exec(event->globalPos());
delete menu;
}
void CodeEditor::resizeEvent(QResizeEvent *event)
{
QPlainTextEdit::resizeEvent(event);
updateSidebarGeometry();
}
void CodeEditor::setTheme(const KSyntaxHighlighting::Theme &theme)
{
auto pal = qApp->palette();
if (theme.isValid()) {
pal.setColor(QPalette::Base, theme.editorColor(KSyntaxHighlighting::Theme::BackgroundColor));
pal.setColor(QPalette::Text, theme.textColor(KSyntaxHighlighting::Theme::Normal));
pal.setColor(QPalette::Highlight, theme.editorColor(KSyntaxHighlighting::Theme::TextSelection));
}
setPalette(pal);
m_highlighter->setTheme(theme);
m_highlighter->rehighlight();
highlightCurrentLine();
}
int CodeEditor::sidebarWidth() const
{
int digits = 1;
auto count = blockCount();
while (count >= 10) {
++digits;
count /= 10;
}
return 4 + fontMetrics().width(QLatin1Char('9')) * digits + fontMetrics().lineSpacing();
}
void CodeEditor::sidebarPaintEvent(QPaintEvent *event)
{
QPainter painter(m_sideBar);
painter.fillRect(event->rect(), m_highlighter->theme().editorColor(KSyntaxHighlighting::Theme::IconBorder));
auto block = firstVisibleBlock();
auto blockNumber = block.blockNumber();
int top = blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top + blockBoundingRect(block).height();
const int currentBlockNumber = textCursor().blockNumber();
const auto foldingMarkerSize = fontMetrics().lineSpacing();
while (block.isValid() && top <= event->rect().bottom()) {
if (block.isVisible() && bottom >= event->rect().top()) {
const auto number = QString::number(blockNumber + 1);
painter.setPen(m_highlighter->theme().editorColor(
(blockNumber == currentBlockNumber) ? KSyntaxHighlighting::Theme::CurrentLineNumber
: KSyntaxHighlighting::Theme::LineNumbers));
painter.drawText(0, top, m_sideBar->width() - 2 - foldingMarkerSize, fontMetrics().height(), Qt::AlignRight, number);
}
// folding marker
if (block.isVisible() && isFoldable(block)) {
QPolygonF polygon;
if (isFolded(block)) {
polygon << QPointF(foldingMarkerSize * 0.4, foldingMarkerSize * 0.25);
polygon << QPointF(foldingMarkerSize * 0.4, foldingMarkerSize * 0.75);
polygon << QPointF(foldingMarkerSize * 0.8, foldingMarkerSize * 0.5);
} else {
polygon << QPointF(foldingMarkerSize * 0.25, foldingMarkerSize * 0.4);
polygon << QPointF(foldingMarkerSize * 0.75, foldingMarkerSize * 0.4);
polygon << QPointF(foldingMarkerSize * 0.5, foldingMarkerSize * 0.8);
}
painter.save();
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(m_highlighter->theme().editorColor(KSyntaxHighlighting::Theme::CodeFolding)));
painter.translate(m_sideBar->width() - foldingMarkerSize, top);
painter.drawPolygon(polygon);
painter.restore();
}
block = block.next();
top = bottom;
bottom = top + blockBoundingRect(block).height();
++blockNumber;
}
}
void CodeEditor::updateSidebarGeometry()
{
setViewportMargins(sidebarWidth(), 0, 0, 0);
const auto r = contentsRect();
m_sideBar->setGeometry(QRect(r.left(), r.top(), sidebarWidth(), r.height()));
}
void CodeEditor::updateSidebarArea(const QRect& rect, int dy)
{
if (dy)
m_sideBar->scroll(0, dy);
else
m_sideBar->update(0, rect.y(), m_sideBar->width(), rect.height());
}
void CodeEditor::highlightCurrentLine()
{
QTextEdit::ExtraSelection selection;
selection.format.setBackground(QColor(m_highlighter->theme().editorColor(KSyntaxHighlighting::Theme::CurrentLine)));
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
QList<QTextEdit::ExtraSelection> extraSelections;
extraSelections.append(selection);
setExtraSelections(extraSelections);
}
QTextBlock CodeEditor::blockAtPosition(int y) const
{
auto block = firstVisibleBlock();
if (!block.isValid())
return QTextBlock();
int top = blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top + blockBoundingRect(block).height();
do {
if (top <= y && y <= bottom)
return block;
block = block.next();
top = bottom;
bottom = top + blockBoundingRect(block).height();
} while (block.isValid());
return QTextBlock();
}
bool CodeEditor::isFoldable(const QTextBlock &block) const
{
return m_highlighter->startsFoldingRegion(block);
}
bool CodeEditor::isFolded(const QTextBlock &block) const
{
if (!block.isValid())
return false;
const auto nextBlock = block.next();
if (!nextBlock.isValid())
return false;
return !nextBlock.isVisible();
}
void CodeEditor::toggleFold(const QTextBlock &startBlock)
{
// we also want to fold the last line of the region, therefore the ".next()"
const auto endBlock = m_highlighter->findFoldingRegionEnd(startBlock).next();
if (isFolded(startBlock)) {
// unfold
auto block = startBlock.next();
while (block.isValid() && !block.isVisible()) {
block.setVisible(true);
block.setLineCount(block.layout()->lineCount());
block = block.next();
}
} else {
// fold
auto block = startBlock.next();
while (block.isValid() && block != endBlock) {
block.setVisible(false);
block.setLineCount(0);
block = block.next();
}
}
// redraw document
document()->markContentsDirty(startBlock.position(), endBlock.position() - startBlock.position() + 1);
// update scrollbars
emit document()->documentLayout()->documentSizeChanged(document()->documentLayout()->documentSize());
}
#include "codeeditor.moc"

View File

@@ -0,0 +1,69 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CODEEDITOR_H
#define CODEEDITOR_H
#include <repository.h>
#include <QPlainTextEdit>
namespace KSyntaxHighlighting {
class SyntaxHighlighter;
}
class CodeEditorSidebar;
class CodeEditor : public QPlainTextEdit
{
Q_OBJECT
public:
explicit CodeEditor(QWidget *parent = nullptr);
~CodeEditor();
void openFile(const QString &fileName);
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
friend class CodeEditorSidebar;
void setTheme(const KSyntaxHighlighting::Theme &theme);
int sidebarWidth() const;
void sidebarPaintEvent(QPaintEvent *event);
void updateSidebarGeometry();
void updateSidebarArea(const QRect &rect, int dy);
void highlightCurrentLine();
QTextBlock blockAtPosition(int y) const;
bool isFoldable(const QTextBlock &block) const;
bool isFolded(const QTextBlock &block) const;
void toggleFold(const QTextBlock &block);
KSyntaxHighlighting::Repository m_repository;
KSyntaxHighlighting::SyntaxHighlighter *m_highlighter;
CodeEditorSidebar *m_sideBar;
};
#endif // CODEEDITOR_H

View File

@@ -0,0 +1,46 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "codeeditor.h"
#include <QApplication>
#include <QCommandLineParser>
#include <QFile>
#include <QTextEdit>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QCommandLineParser parser;
parser.addHelpOption();
parser.addPositionalArgument(QStringLiteral("source"), QStringLiteral("The source file to highlight."));
parser.process(app);
CodeEditor edit;
edit.resize(1024, 1024);
edit.show();
if (parser.positionalArguments().size() == 1)
edit.openFile(parser.positionalArguments().at(0));
return app.exec();
}

View File

@@ -0,0 +1,21 @@
maintainer: vkrause
description: Syntax Highlighting
tier: 1
type: functional
platforms:
- name: Linux
- name: FreeBSD
- name: Windows
- name: MacOSX
- name: Android
portingAid: false
deprecated: false
release: true
libraries:
- qmake: KSyntaxHighlighting
cmake: "KF5::SyntaxHighlighting"
cmakename: KF5SyntaxHighlighting
public_lib: true
group: Frameworks
subgroup: Tier 1

View File

@@ -0,0 +1 @@
org.kde.ksyntaxhighlighting Syntax Highlighting IDENTIFIER [KSyntaxHighlighting::Log]

View File

@@ -0,0 +1,5 @@
add_subdirectory(indexer)
if(TARGET Qt5::Gui)
add_subdirectory(lib)
add_subdirectory(cli)
endif()

View File

@@ -0,0 +1,11 @@
#!/bin/sh
# extract language and section names from XML syntax definition files
# and adapt for lupdate-based extraction to match the rest of the code
$EXTRACTATTR --attr=language,name,Language --attr="language,section,Language Section" ../data/syntax/*.xml >> rc.cpp || exit 12
sed -i -e 's/^i18nc/QT_TRANSLATE_NOOP/' rc.cpp
grep --no-filename '"name"' ../data/themes/*.theme | \
sed -r -e 's/"name"/QT_TRANSLATE_NOOP("Theme", /; s/://; s/,?$/);/' >> rc.cpp
$EXTRACT_TR_STRINGS `find . -name \*.cpp -o -name \*.h -o -name \*.ui -o -name \*.qml` -o $podir/syntaxhighlighting5_qt.pot

View File

@@ -0,0 +1,5 @@
add_executable(kate-syntax-highlighter kate-syntax-highlighter.cpp)
ecm_mark_nongui_executable(kate-syntax-highlighter)
target_link_libraries(kate-syntax-highlighter KF5SyntaxHighlighting)
install(TARGETS kate-syntax-highlighter ${INSTALL_TARGETS_DEFAULT_ARGS})

View File

@@ -0,0 +1,164 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ksyntaxhighlighting_version.h"
#include <definition.h>
#include <definitiondownloader.h>
#include <htmlhighlighter.h>
#include <repository.h>
#include <theme.h>
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QFile>
#include <QVector>
#include <iostream>
using namespace KSyntaxHighlighting;
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName(QStringLiteral("kate-syntax-highlighter"));
QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
QCoreApplication::setApplicationVersion(QStringLiteral(SyntaxHighlighting_VERSION_STRING));
QCommandLineParser parser;
parser.setApplicationDescription(app.translate("SyntaxHighlightingCLI", "Command line syntax highlighter using Kate syntax definitions."));
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument(app.translate("SyntaxHighlightingCLI", "source"),
app.translate("SyntaxHighlightingCLI", "The source file to highlight."));
QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"),
app.translate("SyntaxHighlightingCLI", "List all available syntax definitions."));
parser.addOption(listDefs);
QCommandLineOption listThemes(QStringList() << QStringLiteral("list-themes"),
app.translate("SyntaxHighlightingCLI", "List all available themes."));
parser.addOption(listThemes);
QCommandLineOption updateDefs(QStringList() << QStringLiteral("u") << QStringLiteral("update"),
app.translate("SyntaxHighlightingCLI", "Download new/updated syntax definitions."));
parser.addOption(updateDefs);
QCommandLineOption outputName(QStringList() << QStringLiteral("o") << QStringLiteral("output"),
app.translate("SyntaxHighlightingCLI", "File to write HTML output to (default: stdout)."),
app.translate("SyntaxHighlightingCLI", "output"));
parser.addOption(outputName);
QCommandLineOption syntaxName(QStringList() << QStringLiteral("s") << QStringLiteral("syntax"),
app.translate("SyntaxHighlightingCLI", "Highlight using this syntax definition (default: auto-detect based on input file)."),
app.translate("SyntaxHighlightingCLI", "syntax"));
parser.addOption(syntaxName);
QCommandLineOption themeName(QStringList() << QStringLiteral("t") << QStringLiteral("theme"),
app.translate("SyntaxHighlightingCLI", "Color theme to use for highlighting."),
app.translate("SyntaxHighlightingCLI", "theme"), QStringLiteral("Default"));
parser.addOption(themeName);
QCommandLineOption titleOption(QStringList() << QStringLiteral("T") << QStringLiteral("title"),
app.translate("SyntaxHighlightingCLI", "Set HTML page's title\n(default: the filename or \"Kate Syntax Highlighter\" if reading from stdin)."),
app.translate("SyntaxHighlightingCLI", "title"));
parser.addOption(titleOption);
QCommandLineOption stdinOption(QStringList() << QStringLiteral("stdin"),
app.translate("SyntaxHighlightingCLI", "Read file from stdin. The -s option must also be used."));
parser.addOption(stdinOption);
parser.process(app);
Repository repo;
if (parser.isSet(listDefs)) {
foreach (const auto &def, repo.definitions()) {
std::cout << qPrintable(def.name()) << std::endl;
}
return 0;
}
if (parser.isSet(listThemes)) {
foreach (const auto &theme, repo.themes())
std::cout << qPrintable(theme.name()) << std::endl;
return 0;
}
if (parser.isSet(updateDefs)) {
DefinitionDownloader downloader(&repo);
QObject::connect(&downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) {
std::cout << qPrintable(msg) << std::endl;
});
QObject::connect(&downloader, &DefinitionDownloader::done, &app, &QCoreApplication::quit);
downloader.start();
return app.exec();
}
bool fromFileName = false;
QString inFileName;
if (parser.positionalArguments().size() == 1) {
fromFileName = true;
inFileName = parser.positionalArguments().at(0);
}
Definition def;
if (parser.isSet(syntaxName)) {
def = repo.definitionForName(parser.value(syntaxName));
if (!def.isValid())
/* see if it's a mimetype instead */
def = repo.definitionForMimeType(parser.value(syntaxName));
} else if (fromFileName) {
def = repo.definitionForFileName(inFileName);
} else {
parser.showHelp(1);
}
QString title;
if (parser.isSet(titleOption))
title = parser.value(titleOption);
if (!def.isValid()) {
std::cerr << "Unknown syntax." << std::endl;
return 1;
}
HtmlHighlighter highlighter;
highlighter.setDefinition(def);
if (parser.isSet(outputName))
highlighter.setOutputFile(parser.value(outputName));
else
highlighter.setOutputFile(stdout);
highlighter.setTheme(repo.theme(parser.value(themeName)));
if (fromFileName) {
highlighter.highlightFile(inFileName, title);
} else if (parser.isSet(stdinOption)) {
QFile inFile;
inFile.open(stdin, QIODevice::ReadOnly);
highlighter.highlightData(&inFile, title);
} else {
parser.showHelp(1);
}
return 0;
}

View File

@@ -0,0 +1,36 @@
# when cross compiling, use either the executable offered or try to cross-compile it in place
if(CMAKE_CROSSCOMPILING AND KATEHIGHLIGHTINGINDEXER_EXECUTABLE)
add_executable(katehighlightingindexer IMPORTED GLOBAL)
set_target_properties(katehighlightingindexer PROPERTIES IMPORTED_LOCATION ${KATEHIGHLIGHTINGINDEXER_EXECUTABLE})
elseif(CMAKE_CROSSCOMPILING)
if (NOT KF5_HOST_TOOLING)
message(FATAL_ERROR "Please provide a prefix with a native Qt build and pass -DKF5_HOST_TOOLING=path")
endif()
# search native tooling prefix
string(FIND ${KF5_HOST_TOOLING} /lib idx)
string(SUBSTRING ${KF5_HOST_TOOLING} 0 ${idx} NATIVE_PREFIX)
message(STATUS "Building katehighlightingindexer against ${NATIVE_PREFIX}")
include(ExternalProject)
ExternalProject_Add(native_katehighlightingindexer
SOURCE_DIR ${CMAKE_SOURCE_DIR}
CMAKE_ARGS -DKSYNTAXHIGHLIGHTING_USE_GUI=OFF
-DECM_DIR=${ECM_DIR} -DCMAKE_PREFIX_PATH=${NATIVE_PREFIX}
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
INSTALL_COMMAND ""
)
add_executable(katehighlightingindexer IMPORTED GLOBAL)
add_dependencies(katehighlightingindexer native_katehighlightingindexer)
set_target_properties(katehighlightingindexer PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_BINARY_DIR}/native_katehighlightingindexer-prefix/src/native_katehighlightingindexer-build/bin/katehighlightingindexer)
else()
# host build
add_executable(katehighlightingindexer katehighlightingindexer.cpp)
if(Qt5XmlPatterns_FOUND)
target_link_libraries(katehighlightingindexer Qt5::XmlPatterns)
else()
target_link_libraries(katehighlightingindexer Qt5::Core)
endif()
endif()

View File

@@ -0,0 +1,589 @@
/*
Copyright (C) 2014 Christoph Cullmann <cullmann@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QVariant>
#include <QXmlStreamReader>
#include <QJsonDocument>
#include <QRegularExpression>
#include <QDebug>
#ifdef QT_XMLPATTERNS_LIB
#include <QXmlSchema>
#include <QXmlSchemaValidator>
#endif
namespace {
QStringList readListing(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
return QStringList();
}
QXmlStreamReader xml(&file);
QStringList listing;
while (!xml.atEnd()) {
xml.readNext();
// add only .xml files, no .json or stuff
if (xml.isCharacters() && xml.text().toString().contains(QLatin1String(".xml"))) {
listing.append(xml.text().toString());
}
}
if (xml.hasError()) {
qWarning() << "XML error while reading" << fileName << " - "
<< qPrintable(xml.errorString()) << "@ offset" << xml.characterOffset();
}
return listing;
}
/**
* check if the "extensions" attribute have valid wildcards
* @param extensions extensions string to check
* @return valid?
*/
bool checkExtensions(QString extensions)
{
// get list of extensions
const QStringList extensionParts = extensions.split(QLatin1Char(';'), QString::SkipEmptyParts);
// ok if empty
if (extensionParts.isEmpty()) {
return true;
}
// check that only valid wildcard things are inside the parts
for (const auto& extension : extensionParts) {
for (const auto c : extension) {
// eat normal things
if (c.isDigit() || c.isLetter()) {
continue;
}
// allow some special characters
if (c == QLatin1Char('.') || c == QLatin1Char('-') || c == QLatin1Char('_') || c == QLatin1Char('+')) {
continue;
}
// only allowed wildcard things: '?' and '*'
if (c == QLatin1Char('?') || c == QLatin1Char('*')) {
continue;
}
qWarning() << "invalid character" << c << " seen in extensions wildcard";
return false;
}
}
// all checks passed
return true;
}
//! Check that a regular expression in a RegExpr rule:
//! - is not empty
//! - isValid()
//! - character ranges such as [A-Z] are valid and not accidentally e.g. [A-z].
bool checkRegularExpression(const QString &hlFilename, QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("RegExpr") || xml.name() == QLatin1String("emptyLine")) {
// get right attribute
const QString string (xml.attributes().value((xml.name() == QLatin1String("RegExpr")) ? QLatin1String("String") : QLatin1String("regexpr")).toString());
// validate regexp
const QRegularExpression regexp (string);
if (!regexp.isValid()) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "broken regex:" << string << "problem:" << regexp.errorString() << "at offset" << regexp.patternErrorOffset();
return false;
} else if (string.isEmpty()) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "empty regex not allowed.";
return false;
}
// catch possible case typos: [A-z] or [a-Z]
const int azOffset = std::max(string.indexOf(QStringLiteral("A-z")), string.indexOf(QStringLiteral("a-Z")));
if (azOffset >= 0) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "broken regex:" << string << "problem: [a-Z] or [A-z] at offset" << azOffset;
return false;
}
}
return true;
}
//! Check that keyword list items do not have trailing or leading spaces,
//! e.g.: <item> keyword </item>
bool checkItemsTrimmed(const QString &hlFilename, QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("item")) {
const QString keyword = xml.readElementText();
if (keyword != keyword.trimmed()) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "keyword with leading/trailing spaces:" << keyword;
return false;
}
}
return true;
}
//! Checks that DetectChar and Detect2Chars really only have one char
//! in the attributes 'char' and 'char1'.
bool checkSingleChars(const QString &hlFilename, QXmlStreamReader &xml)
{
const bool testChar1 = xml.name() == QLatin1String("Detect2Chars");
const bool testChar = testChar1 || xml.name() == QLatin1String("DetectChar");
if (testChar) {
const QString c = xml.attributes().value(QLatin1String("char")).toString();
if (c.size() != 1) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "'char' must contain exactly one char:" << c;
}
}
if (testChar1) {
const QString c = xml.attributes().value(QLatin1String("char1")).toString();
if (c.size() != 1) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "'char1' must contain exactly one char:" << c;
}
}
return true;
}
//! Search for rules with lookAhead="true" and context="#stay".
//! This would cause an infinite loop.
bool checkLookAhead(const QString &hlFilename, QXmlStreamReader &xml)
{
if (xml.attributes().hasAttribute(QStringLiteral("lookAhead"))) {
auto lookAhead = xml.attributes().value(QStringLiteral("lookAhead"));
if (lookAhead == QStringLiteral("true")) {
auto context = xml.attributes().value(QStringLiteral("context"));
if (context == QStringLiteral("#stay")) {
qWarning() << hlFilename << "line" << xml.lineNumber() << "Infinite loop: lookAhead with context #stay";
return false;
}
}
}
return true;
}
/**
* Helper class to search for non-existing or unreferenced keyword lists.
*/
class KeywordChecker
{
public:
KeywordChecker(const QString &filename)
: m_filename(filename)
{}
void processElement(QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("list")) {
const QString name = xml.attributes().value(QLatin1String("name")).toString();
if (m_existingNames.contains(name)) {
qWarning() << m_filename << "list duplicate:" << name;
}
m_existingNames.insert(name);
} else if (xml.name() == QLatin1String("keyword")) {
const QString context = xml.attributes().value(QLatin1String("String")).toString();
if (!context.isEmpty())
m_usedNames.insert(context);
}
}
bool check() const
{
bool success = true;
const auto invalidNames = m_usedNames - m_existingNames;
if (!invalidNames.isEmpty()) {
qWarning() << m_filename << "Reference of non-existing keyword list:" << invalidNames;
success = false;
}
const auto unusedNames = m_existingNames - m_usedNames;
if (!unusedNames.isEmpty()) {
qWarning() << m_filename << "Unused keyword lists:" << unusedNames;
}
return success;
}
private:
QString m_filename;
QSet<QString> m_usedNames;
QSet<QString> m_existingNames;
};
/**
* Helper class to search for non-existing contexts
*/
class ContextChecker
{
public:
void processElement(const QString &hlFilename, const QString &hlName, QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("context")) {
auto & language = m_contextMap[hlName];
language.hlFilename = hlFilename;
const QString name = xml.attributes().value(QLatin1String("name")).toString();
if (language.isFirstContext) {
language.isFirstContext = false;
language.usedContextNames.insert(name);
}
if (language.existingContextNames.contains(name)) {
qWarning() << hlFilename << "Duplicate context:" << name;
} else {
language.existingContextNames.insert(name);
}
if (xml.attributes().value(QLatin1String("fallthroughContext")).toString() == QLatin1String("#stay")) {
qWarning() << hlFilename << "possible infinite loop due to fallthroughContext=\"#stay\" in context " << name;
}
processContext(hlName, xml.attributes().value(QLatin1String("lineEndContext")).toString());
processContext(hlName, xml.attributes().value(QLatin1String("lineEmptyContext")).toString());
processContext(hlName, xml.attributes().value(QLatin1String("fallthroughContext")).toString());
} else {
if (xml.attributes().hasAttribute(QLatin1String("context"))) {
const QString context = xml.attributes().value(QLatin1String("context")).toString();
if (context.isEmpty()) {
qWarning() << hlFilename << "Missing context name in line" << xml.lineNumber();
} else {
processContext(hlName, context);
}
}
}
}
bool check() const
{
bool success = true;
for (auto &language : m_contextMap) {
const auto invalidContextNames = language.usedContextNames - language.existingContextNames;
if (!invalidContextNames.isEmpty()) {
qWarning() << language.hlFilename << "Reference of non-existing contexts:" << invalidContextNames;
success = false;
}
const auto unusedNames = language.existingContextNames - language.usedContextNames;
if (!unusedNames.isEmpty()) {
qWarning() << language.hlFilename << "Unused contexts:" << unusedNames;
}
}
return success;
}
private:
//! Extract the referenced context name and language.
//! Some input / output examples are:
//! - "#stay" -> ""
//! - "#pop" -> ""
//! - "Comment" -> "Comment"
//! - "#pop!Comment" -> "Comment"
//! - "##ISO C++" -> ""
//! - "Comment##ISO C++"-> "Comment" in ISO C++
void processContext(const QString &language, QString context)
{
if (context.isEmpty())
return;
// filter out #stay and #pop
static QRegularExpression stayPop(QStringLiteral("^(#stay|#pop)+"));
context.remove(stayPop);
// handle cross-language context references
if (context.contains(QStringLiteral("##"))) {
const QStringList list = context.split(QStringLiteral("##"), QString::SkipEmptyParts);
if (list.size() == 1) {
// nothing to do, other language is included: e.g. ##Doxygen
} else if (list.size() == 2) {
// specific context of other language, e.g. Comment##ISO C++
m_contextMap[list[1]].usedContextNames.insert(list[0]);
}
return;
}
// handle #pop!context" (#pop was already removed above)
if (context.startsWith(QLatin1Char('!')))
context.remove(0, 1);
if (!context.isEmpty())
m_contextMap[language].usedContextNames.insert(context);
}
private:
class Language
{
public:
// filename on disk or in Qt resource
QString hlFilename;
// Is true, if the first context in xml file is encountered, and
// false in all other cases. This is required, since the first context
// is typically not referenced explicitly. So we will simply add the
// first context to the usedContextNames list.
bool isFirstContext = true;
// holds all contexts that were referenced
QSet<QString> usedContextNames;
// holds all existing context names
QSet<QString> existingContextNames;
};
/**
* "Language name" to "Language" map.
* Example key: "Doxygen"
*/
QHash<QString, Language> m_contextMap;
};
/**
* Helper class to search for non-existing itemDatas.
*/
class AttributeChecker
{
public:
AttributeChecker(const QString &filename)
: m_filename(filename)
{}
void processElement(QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("itemData")) {
const QString name = xml.attributes().value(QLatin1String("name")).toString();
if (!name.isEmpty()) {
if (m_existingAttributeNames.contains(name)) {
qWarning() << m_filename << "itemData duplicate:" << name;
} else {
m_existingAttributeNames.insert(name);
}
}
} else if (xml.attributes().hasAttribute(QLatin1String("attribute"))) {
const QString name = xml.attributes().value(QLatin1String("attribute")).toString();
if (name.isEmpty()) {
qWarning() << m_filename << "specified attribute is empty:" << xml.name();
} else {
m_usedAttributeNames.insert(name);
}
}
}
bool check() const
{
bool success = true;
const auto invalidNames = m_usedAttributeNames - m_existingAttributeNames;
if (!invalidNames.isEmpty()) {
qWarning() << m_filename << "Reference of non-existing itemData attributes:" << invalidNames;
success = false;
}
auto unusedNames = m_existingAttributeNames - m_usedAttributeNames;
if (!unusedNames.isEmpty()) {
qWarning() << m_filename << "Unused itemData:" << unusedNames;
}
return success;
}
private:
QString m_filename;
QSet<QString> m_usedAttributeNames;
QSet<QString> m_existingAttributeNames;
};
}
int main(int argc, char *argv[])
{
// get app instance
QCoreApplication app(argc, argv);
// ensure enough arguments are passed
if (app.arguments().size() < 3)
return 1;
#ifdef QT_XMLPATTERNS_LIB
// open schema
QXmlSchema schema;
if (!schema.load(QUrl::fromLocalFile(app.arguments().at(2))))
return 2;
#endif
const QString hlFilenamesListing = app.arguments().value(3);
if (hlFilenamesListing.isEmpty()) {
return 1;
}
QStringList hlFilenames = readListing(hlFilenamesListing);
if (hlFilenames.isEmpty()) {
qWarning("Failed to read %s", qPrintable(hlFilenamesListing));
return 3;
}
// text attributes
const QStringList textAttributes = QStringList() << QStringLiteral("name") << QStringLiteral("section") << QStringLiteral("mimetype")
<< QStringLiteral("extensions") << QStringLiteral("style")
<< QStringLiteral("author") << QStringLiteral("license") << QStringLiteral("indenter");
// index all given highlightings
ContextChecker contextChecker;
QVariantMap hls;
int anyError = 0;
foreach (const QString &hlFilename, hlFilenames) {
QFile hlFile(hlFilename);
if (!hlFile.open(QIODevice::ReadOnly)) {
qWarning ("Failed to open %s", qPrintable(hlFilename));
anyError = 3;
continue;
}
#ifdef QT_XMLPATTERNS_LIB
// validate against schema
QXmlSchemaValidator validator(schema);
if (!validator.validate(&hlFile, QUrl::fromLocalFile(hlFile.fileName()))) {
anyError = 4;
continue;
}
#endif
// read the needed attributes from toplevel language tag
hlFile.reset();
QXmlStreamReader xml(&hlFile);
if (xml.readNextStartElement()) {
if (xml.name() != QLatin1String("language")) {
anyError = 5;
continue;
}
} else {
anyError = 6;
continue;
}
// map to store hl info
QVariantMap hl;
// transfer text attributes
Q_FOREACH (const QString &attribute, textAttributes) {
hl[attribute] = xml.attributes().value(attribute).toString();
}
// check if extensions have the right format
if (!checkExtensions(hl[QStringLiteral("extensions")].toString())) {
qWarning() << hlFilename << "'extensions' wildcards invalid:" << hl[QStringLiteral("extensions")].toString();
anyError = 23;
}
// numerical attributes
hl[QStringLiteral("version")] = xml.attributes().value(QLatin1String("version")).toInt();
hl[QStringLiteral("priority")] = xml.attributes().value(QLatin1String("priority")).toInt();
// add boolean one
const QString hidden = xml.attributes().value(QLatin1String("hidden")).toString();
hl[QStringLiteral("hidden")] = (hidden == QLatin1String("true") || hidden == QLatin1String("1"));
// remember hl
hls[QFileInfo(hlFile).fileName()] = hl;
AttributeChecker attributeChecker(hlFilename);
KeywordChecker keywordChecker(hlFilename);
const QString hlName = hl[QStringLiteral("name")].toString();
// scan for broken regex or keywords with spaces
while (!xml.atEnd()) {
xml.readNext();
if (!xml.isStartElement()) {
continue;
}
// search for used/existing contexts if applicable
contextChecker.processElement(hlFilename, hlName, xml);
// search for used/existing attributes if applicable
attributeChecker.processElement(xml);
// search for used/existing keyword lists if applicable
keywordChecker.processElement(xml);
// scan for bad regex
if (!checkRegularExpression(hlFilename, xml)) {
anyError = 7;
continue;
}
// scan for bogus <item> lala </item> spaces
if (!checkItemsTrimmed(hlFilename, xml)) {
anyError = 8;
continue;
}
// check single chars in DetectChar and Detect2Chars
if (!checkSingleChars(hlFilename, xml)) {
anyError = 8;
continue;
}
// scan for lookAhead="true" with context="#stay"
if (!checkLookAhead(hlFilename, xml)) {
anyError = 7;
continue;
}
}
if (!attributeChecker.check()) {
anyError = 7;
}
if (!keywordChecker.check()) {
anyError = 7;
}
}
if (!contextChecker.check())
anyError = 7;
// bail out if any problem was seen
if (anyError)
return anyError;
// create outfile, after all has worked!
QFile outFile(app.arguments().at(1));
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
return 9;
// write out json
outFile.write(QJsonDocument::fromVariant(QVariant(hls)).toBinaryData());
// be done
return 0;
}

View File

@@ -0,0 +1,86 @@
ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting5_qt)
set(syntax_highlighting_srcs
abstracthighlighter.cpp
context.cpp
contextswitch.cpp
definitiondownloader.cpp
foldingregion.cpp
format.cpp
htmlhighlighter.cpp
keywordlist.cpp
rule.cpp
definition.cpp
repository.cpp
state.cpp
syntaxhighlighter.cpp
theme.cpp
wildcardmatcher.cpp
themedata.cpp
${syntax_highlighting_QM_LOADER}
)
ecm_qt_declare_logging_category(syntax_highlighting_srcs
HEADER ksyntaxhighlighting_logging.h
IDENTIFIER KSyntaxHighlighting::Log
CATEGORY_NAME org.kde.ksyntaxhighlighting
)
add_library(KF5SyntaxHighlighting ${syntax_highlighting_srcs} $<TARGET_OBJECTS:SyntaxHighlightingData>)
generate_export_header(KF5SyntaxHighlighting BASE_NAME KSyntaxHighlighting)
set_target_properties(KF5SyntaxHighlighting PROPERTIES
VERSION ${SyntaxHighlighting_VERSION_STRING}
SOVERSION ${SyntaxHighlighting_SOVERSION}
EXPORT_NAME SyntaxHighlighting
)
target_include_directories(KF5SyntaxHighlighting INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting;${KDE_INSTALL_INCLUDEDIR_KF5}>")
target_include_directories(KF5SyntaxHighlighting PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR};>")
target_link_libraries(KF5SyntaxHighlighting LINK_PUBLIC Qt5::Gui LINK_PRIVATE Qt5::Network)
ecm_generate_headers(SyntaxHighlighting_HEADERS
HEADER_NAMES
AbstractHighlighter
Definition
FoldingRegion
Format
Repository
State
SyntaxHighlighter
Theme
REQUIRED_HEADERS SyntaxHighlighting_HEADERS
)
install(TARGETS KF5SyntaxHighlighting EXPORT KF5SyntaxHighlightingTargets ${INSTALL_TARGETS_DEFAULT_ARGS})
install(FILES
${SyntaxHighlighting_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_export.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting)
if(BUILD_QCH)
ecm_add_qch(
KF5SyntaxHighlighting_QCH
NAME KSyntaxHighlighting
BASE_NAME KF5SyntaxHighlighting
VERSION ${KF5_VERSION}
ORG_DOMAIN org.kde
SOURCES # using only public headers, to cover only public API
${SyntaxHighlighting_HEADERS}
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
LINK_QCHS
Qt5Core_QCH
Qt5Gui_QCH
BLANK_MACROS
KSYNTAXHIGHLIGHTING_EXPORT
KSYNTAXHIGHLIGHTING_DEPRECATED
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
COMPONENT Devel
)
endif()
ecm_generate_pri_file(
BASE_NAME KSyntaxHighlighting LIB_NAME
KF5SyntaxHighlighting
DEPS "gui"
FILENAME_VAR PRI_FILENAME
INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting
)
install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})

View File

@@ -0,0 +1,328 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "abstracthighlighter.h"
#include "abstracthighlighter_p.h"
#include "context_p.h"
#include "definition_p.h"
#include "foldingregion.h"
#include "format.h"
#include "repository.h"
#include "rule_p.h"
#include "state.h"
#include "state_p.h"
#include "ksyntaxhighlighting_logging.h"
#include "theme.h"
using namespace KSyntaxHighlighting;
AbstractHighlighterPrivate::AbstractHighlighterPrivate()
{
}
AbstractHighlighterPrivate::~AbstractHighlighterPrivate()
{
}
void AbstractHighlighterPrivate::ensureDefinitionLoaded()
{
auto defData = DefinitionData::get(m_definition);
if (Q_UNLIKELY(!m_definition.isValid() && defData->repo && !m_definition.name().isEmpty())) {
qCDebug(Log) << "Definition became invalid, trying re-lookup.";
m_definition = defData->repo->definitionForName(m_definition.name());
defData = DefinitionData::get(m_definition);
}
if (Q_UNLIKELY(!defData->repo && !defData->name.isEmpty()))
qCCritical(Log) << "Repository got deleted while a highlighter is still active!";
if (m_definition.isValid())
defData->load();
}
AbstractHighlighter::AbstractHighlighter() :
d_ptr(new AbstractHighlighterPrivate)
{
}
AbstractHighlighter::AbstractHighlighter(AbstractHighlighterPrivate *dd) :
d_ptr(dd)
{
}
AbstractHighlighter::~AbstractHighlighter()
{
delete d_ptr;
}
Definition AbstractHighlighter::definition() const
{
return d_ptr->m_definition;
}
void AbstractHighlighter::setDefinition(const Definition &def)
{
Q_D(AbstractHighlighter);
d->m_definition = def;
}
Theme AbstractHighlighter::theme() const
{
Q_D(const AbstractHighlighter);
return d->m_theme;
}
void AbstractHighlighter::setTheme(const Theme &theme)
{
Q_D(AbstractHighlighter);
d->m_theme = theme;
}
/**
* Returns the index of the first non-space character. If the line is empty,
* or only contains white spaces, text.size() is returned.
*/
static inline int firstNonSpaceChar(const QString & text)
{
for (int i = 0; i < text.length(); ++i) {
if (!text[i].isSpace()) {
return i;
}
}
return text.size();
}
State AbstractHighlighter::highlightLine(const QString& text, const State &state)
{
Q_D(AbstractHighlighter);
// verify definition, deal with no highlighting being enabled
d->ensureDefinitionLoaded();
if (!d->m_definition.isValid()) {
applyFormat(0, text.size(), Format());
return State();
}
// verify/initialize state
auto defData = DefinitionData::get(d->m_definition);
auto newState = state;
auto stateData = StateData::get(newState);
const DefinitionRef currentDefRef(d->m_definition);
if (!stateData->isEmpty() && (stateData->m_defRef != currentDefRef)) {
qCDebug(Log) << "Got invalid state, resetting.";
stateData->clear();
}
if (stateData->isEmpty()) {
stateData->push(defData->initialContext(), QStringList());
stateData->m_defRef = currentDefRef;
}
// process empty lines
if (text.isEmpty()) {
while (!stateData->topContext()->lineEmptyContext().isStay()) {
if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList()))
break;
}
auto context = stateData->topContext();
applyFormat(0, 0, context->attributeFormat());
return newState;
}
int offset = 0, beginOffset = 0;
bool lineContinuation = false;
QHash<Rule*, int> skipOffsets;
/**
* current active format
* stored as pointer to avoid deconstruction/constructions inside the internal loop
* the pointers are stable, the formats are either in the contexts or rules
*/
auto currentFormat = &stateData->topContext()->attributeFormat();
/**
* cached first non-space character, needs to be computed if < 0
*/
int firstNonSpace = -1;
int lastOffset = offset;
int endlessLoopingCounter = 0;
do {
/**
* avoid that we loop endless for some broken hl definitions
*/
if (lastOffset == offset) {
++endlessLoopingCounter;
if (endlessLoopingCounter > 1024) {
qCDebug(Log) << "Endless state transitions, aborting highlighting of line.";
break;
}
} else {
// ensure we made progress, clear the endlessLoopingCounter
Q_ASSERT(offset > lastOffset);
lastOffset = offset;
endlessLoopingCounter = 0;
}
/**
* try to match all rules in the context in order of declaration in XML
*/
bool isLookAhead = false;
int newOffset = 0;
const Format *newFormat = nullptr;
for (const auto &rule : stateData->topContext()->rules()) {
/**
* filter out rules that require a specific column
*/
if ((rule->requiredColumn() >= 0) && (rule->requiredColumn() != offset)) {
continue;
}
/**
* filter out rules that only match for leading whitespace
*/
if (rule->firstNonSpace()) {
/**
* compute the first non-space lazy
* avoids computing it for contexts without any such rules
*/
if (firstNonSpace < 0) {
firstNonSpace = firstNonSpaceChar(text);
}
/**
* can we skip?
*/
if (offset > firstNonSpace) {
continue;
}
}
/**
* shall we skip application of this rule? two cases:
* - rule can't match at all => currentSkipOffset < 0
* - rule will only match for some higher offset => currentSkipOffset > offset
*/
const auto currentSkipOffset = skipOffsets.value(rule.get());
if (currentSkipOffset < 0 || currentSkipOffset > offset)
continue;
const auto newResult = rule->doMatch(text, offset, stateData->topCaptures());
newOffset = newResult.offset();
/**
* update skip offset if new one rules out any later match or is larger than current one
*/
if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset)
skipOffsets.insert(rule.get(), newResult.skipOffset());
if (newOffset <= offset)
continue;
// apply folding
if (rule->endRegion().isValid())
applyFolding(offset, newOffset - offset, rule->endRegion());
if (rule->beginRegion().isValid())
applyFolding(offset, newOffset - offset, rule->beginRegion());
if (rule->isLookAhead()) {
Q_ASSERT(!rule->context().isStay());
d->switchContext(stateData, rule->context(), newResult.captures());
isLookAhead = true;
break;
}
d->switchContext(stateData, rule->context(), newResult.captures());
newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat();
if (newOffset == text.size() && std::dynamic_pointer_cast<LineContinue>(rule))
lineContinuation = true;
break;
}
if (isLookAhead)
continue;
if (newOffset <= offset) { // no matching rule
if (stateData->topContext()->fallthrough()) {
d->switchContext(stateData, stateData->topContext()->fallthroughContext(), QStringList());
continue;
}
newOffset = offset + 1;
newFormat = &stateData->topContext()->attributeFormat();
}
/**
* if we arrive here, some new format has to be set!
*/
Q_ASSERT(newFormat);
/**
* on format change, apply the last one and switch to new one
*/
if (newFormat != currentFormat && newFormat->id() != currentFormat->id()) {
if (offset > 0)
applyFormat(beginOffset, offset - beginOffset, *currentFormat);
beginOffset = offset;
currentFormat = newFormat;
}
/**
* we must have made progress if we arrive here!
*/
Q_ASSERT(newOffset > offset);
offset = newOffset;
} while (offset < text.size());
if (beginOffset < offset)
applyFormat(beginOffset, text.size() - beginOffset, *currentFormat);
while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) {
if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList()))
break;
}
return newState;
}
bool AbstractHighlighterPrivate::switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures)
{
// kill as many items as requested from the stack, will always keep the initial context alive!
const bool initialContextSurvived = data->pop(contextSwitch.popCount());
// if we have a new context to add, push it
// then we always "succeed"
if (contextSwitch.context()) {
data->push(contextSwitch.context(), captures);
return true;
}
// else we abort, if we did try to pop the initial context
return initialContextSurvived;
}
void AbstractHighlighter::applyFolding(int offset, int length, FoldingRegion region)
{
Q_UNUSED(offset);
Q_UNUSED(length);
Q_UNUSED(region);
}

View File

@@ -0,0 +1,195 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H
#define KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H
#include "ksyntaxhighlighting_export.h"
#include <QObject>
#include <memory>
QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class AbstractHighlighterPrivate;
class Definition;
class FoldingRegion;
class Format;
class State;
class Theme;
/**
* Abstract base class for highlighters.
*
* @section abshl_intro Introduction
*
* The AbstractHighlighter provides an interface to highlight text.
*
* The SyntaxHighlighting framework already ships with one implementation,
* namely the SyntaxHighlighter, which also derives from QSyntaxHighlighter,
* meaning that it can be used to highlight a QTextDocument or a QML TextEdit.
* In order to use the SyntaxHighlighter, just call setDefinition() and
* setTheme(), and the associated documents will automatically be highlighted.
*
* However, if you want to use the SyntaxHighlighting framework to implement
* your own syntax highlighter, you need to sublcass from AbstractHighlighter.
*
* @section abshl_impl Implementing your own Syntax Highlighter
*
* In order to implement your own syntax highlighter, you need to inherit from
* AbstractHighlighter. Then, pass each text line that needs to be highlighted
* in order to highlightLine(). Internally, highlightLine() uses the Definition
* initially set through setDefinition() and the State of the previous text line
* to parse and highlight the given text line. For each visual highlighting
* change, highlightLine() will call applyFormat(). Therefore, reimplement
* applyFormat() to get notified of the Format that is valid in the range
* starting at the given offset with the specified length. Similarly, for each
* text part that starts or ends a code folding region, highlightLine() will
* call applyFolding(). Therefore, if you are interested in code folding,
* reimplement applyFolding() to get notified of the starting and ending code
* folding regions, again specified in the range starting at the given offset
* with the given length.
*
* The Format class itself depends on the current Theme. A theme must be
* initially set once such that the Format%s instances can be queried for
* concrete colors.
*
* Optionally, you can also reimplement setTheme() and setDefinition() to get
* notified whenever the Definition or the Theme changes.
*
* @see SyntaxHighlighter
* @since 5.28
*/
class KSYNTAXHIGHLIGHTING_EXPORT AbstractHighlighter
{
public:
virtual ~AbstractHighlighter();
/**
* Returns the syntax definition used for highlighting.
*
* @see setDefinition()
*/
Definition definition() const;
/**
* Sets the syntax definition used for highlighting.
*
* Subclasses can re-implement this method to e.g. trigger
* re-highlighting or clear internal data structures if needed.
*/
virtual void setDefinition(const Definition &def);
/**
* Returns the currently selected theme for highlighting.
*
* @note If no Theme was set through setTheme(), the returned Theme will be
* invalid, see Theme::isValid().
*/
Theme theme() const;
/**
* Sets the theme used for highlighting.
*
* Subclasses can re-implement this method to e.g. trigger
* re-highlighing or to do general palette color setup.
*/
virtual void setTheme(const Theme &theme);
protected:
AbstractHighlighter();
AbstractHighlighter(AbstractHighlighterPrivate *dd);
// TODO KF6: add an optional void* context argument that is passed through
// to the applyX() calls, so highlighters dealing with some form of line object
// (such as QSyntaxHighlighter or KTextEditor) can avoid some ugly hacks to have
// this context available in their applyX methods
/**
* Highlight the given line. Call this from your derived class
* where appropriate. This will result in any number of applyFormat()
* and applyFolding() calls as a result.
* @param text A string containing the text of the line to highlight.
* @param state The highlighting state handle returned by the call
* to highlightLine() for the previous line. For the very first line,
* just pass a default constructed State().
* @returns The state of the highlighing engine after processing the
* given line. This needs to passed into highlightLine() for the
* next line. You can store the state for efficient partial
* re-highlighting for example during editing.
*
* @see applyFormat(), applyFolding()
*/
State highlightLine(const QString &text, const State &state);
/**
* Reimplement this to apply formats to your output. The provided @p format
* is valid for the interval [@p offset, @p offset + @p length).
*
* @param offset The start column of the interval for which @p format matches
* @param length The length of the matching text
* @param format The Format that applies to the range [offset, offset + length)
*
* @note Make sure to set a valid Definition, otherwise the parameter
* @p format is invalid for the entire line passed to highlightLine()
* (cf. Format::isValid()).
*
* @see applyFolding(), highlightLine()
*/
virtual void applyFormat(int offset, int length, const Format &format) = 0;
/**
* Reimplement this to apply folding to your output. The provided
* FoldingRegion @p region either stars or ends a code folding region in the
* interval [@p offset, @p offset + @p length).
*
* @param offset The start column of the FoldingRegion
* @param length The length of the matching text that starts / ends a
* folding region
* @param region The FoldingRegion that applies to the range [offset, offset + length)
*
* @note The FoldingRegion @p region is @e always either of type
* FoldingRegion::Type::Begin or FoldingRegion::Type::End.
*
* @see applyFormat(), highlightLine(), FoldingRegion
*/
virtual void applyFolding(int offset, int length, FoldingRegion region);
protected:
AbstractHighlighterPrivate *d_ptr;
private:
Q_DECLARE_PRIVATE(AbstractHighlighter)
Q_DISABLE_COPY(AbstractHighlighter)
};
}
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(KSyntaxHighlighting::AbstractHighlighter, "org.kde.SyntaxHighlighting.AbstractHighlighter")
QT_END_NAMESPACE
#endif // KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H

View File

@@ -0,0 +1,54 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTER_P_H
#define KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTER_P_H
#include "definition.h"
#include "theme.h"
QT_BEGIN_NAMESPACE
class QStringList;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class ContextSwitch;
class StateData;
class AbstractHighlighterPrivate
{
public:
AbstractHighlighterPrivate();
virtual ~AbstractHighlighterPrivate();
void ensureDefinitionLoaded();
bool switchContext(StateData* data, const ContextSwitch &contextSwitch, const QStringList &captures);
Definition m_definition;
Theme m_theme;
};
}
#endif

View File

@@ -0,0 +1,206 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "context_p.h"
#include "definition_p.h"
#include "format.h"
#include "repository.h"
#include "rule_p.h"
#include "ksyntaxhighlighting_logging.h"
#include "xml_p.h"
#include <QString>
#include <QXmlStreamReader>
using namespace KSyntaxHighlighting;
Definition Context::definition() const
{
return m_def.definition();
}
void Context::setDefinition(const DefinitionRef &def)
{
m_def = def;
}
bool Context::indentationBasedFoldingEnabled() const
{
if (m_noIndentationBasedFolding)
return false;
return m_def.definition().indentationBasedFoldingEnabled();
}
void Context::load(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("context"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
m_name = reader.attributes().value(QStringLiteral("name")).toString();
m_attribute = reader.attributes().value(QStringLiteral("attribute")).toString();
m_lineEndContext.parse(reader.attributes().value(QStringLiteral("lineEndContext")));
m_lineEmptyContext.parse(reader.attributes().value(QStringLiteral("lineEmptyContext")));
m_fallthrough = Xml::attrToBool(reader.attributes().value(QStringLiteral("fallthrough")));
m_fallthroughContext.parse(reader.attributes().value(QStringLiteral("fallthroughContext")));
if (m_fallthroughContext.isStay())
m_fallthrough = false;
m_noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("noIndentationBasedFolding")));
reader.readNext();
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
{
auto rule = Rule::create(reader.name());
if (rule) {
rule->setDefinition(m_def.definition());
if (rule->load(reader))
m_rules.push_back(rule);
} else {
reader.skipCurrentElement();
}
reader.readNext();
break;
}
case QXmlStreamReader::EndElement:
return;
default:
reader.readNext();
break;
}
}
}
void Context::resolveContexts()
{
const auto def = m_def.definition();
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;
if (resolveState() == Resolving) {
qCWarning(Log) << "Cyclic dependency!";
return;
}
Q_ASSERT(resolveState() == Unresolved);
m_resolveState = Resolving; // cycle guard
for (auto it = m_rules.begin(); it != m_rules.end();) {
auto inc = std::dynamic_pointer_cast<IncludeRules>(*it);
if (!inc) {
++it;
continue;
}
Context* context = nullptr;
auto myDefData = DefinitionData::get(m_def.definition());
if (inc->definitionName().isEmpty()) { // local include
context = myDefData->contextByName(inc->contextName());
} else {
auto def = myDefData->repo->definitionForName(inc->definitionName());
if (!def.isValid()) {
qCWarning(Log) << "Unable to resolve external include rule for definition" << inc->definitionName() << "in" << m_def.definition().name();
++it;
continue;
}
auto defData = DefinitionData::get(def);
defData->load();
if (inc->contextName().isEmpty())
context = defData->initialContext();
else
context = defData->contextByName(inc->contextName());
}
if (!context) {
qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in" << m_def.definition().name();
++it;
continue;
}
context->resolveIncludes();
/**
* handle included attribute
* transitive closure: we might include attributes included from somewhere else
*/
if (inc->includeAttribute()) {
m_attribute = context->m_attribute;
m_attributeContext = context->m_attributeContext ? context->m_attributeContext : context;
}
it = m_rules.erase(it);
for (const auto &rule : context->rules()) {
it = m_rules.insert(it, rule);
++it;
}
}
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);
}
}

View File

@@ -0,0 +1,139 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_CONTEXT_P_H
#define KSYNTAXHIGHLIGHTING_CONTEXT_P_H
#include "rule_p.h"
#include "contextswitch_p.h"
#include "definition.h"
#include "definitionref_p.h"
#include "format.h"
#include <QString>
#include <vector>
QT_BEGIN_NAMESPACE
class QXmlStreamReader;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class Context
{
public:
Context() = default;
~Context() = default;
Definition definition() const;
void setDefinition(const DefinitionRef &def);
const QString &name() const
{
return m_name;
}
const ContextSwitch &lineEndContext() const
{
return m_lineEndContext;
}
const ContextSwitch &lineEmptyContext() const
{
return m_lineEmptyContext;
}
bool fallthrough() const
{
return m_fallthrough;
}
const ContextSwitch &fallthroughContext() const
{
return m_fallthroughContext;
}
const Format &attributeFormat() const
{
return m_attributeFormat;
}
const std::vector<Rule::Ptr> &rules() const
{
return m_rules;
}
/**
* Returns @c true, when indentationBasedFolding is enabled for the
* associated Definition and when "noIndentationBasedFolding" is NOT set.
*/
bool indentationBasedFoldingEnabled() const;
void load(QXmlStreamReader &reader);
void resolveContexts();
void resolveIncludes();
void resolveAttributeFormat();
private:
Q_DISABLE_COPY(Context)
enum ResolveState {
Unknown,
Unresolved,
Resolving,
Resolved
};
ResolveState resolveState();
DefinitionRef m_def;
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_lineEmptyContext;
ContextSwitch m_fallthroughContext;
std::vector<Rule::Ptr> m_rules;
ResolveState m_resolveState = Unknown;
bool m_fallthrough = false;
bool m_noIndentationBasedFolding = false;
};
}
#endif // KSYNTAXHIGHLIGHTING_CONTEXT_P_H

View File

@@ -0,0 +1,90 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "contextswitch_p.h"
#include "definition.h"
#include "definition_p.h"
#include "repository.h"
#include "ksyntaxhighlighting_logging.h"
using namespace KSyntaxHighlighting;
bool ContextSwitch::isStay() const
{
return m_popCount == 0 && !m_context && m_contextName.isEmpty() && m_defName.isEmpty();
}
int ContextSwitch::popCount() const
{
return m_popCount;
}
Context* ContextSwitch::context() const
{
return m_context;
}
void ContextSwitch::parse(const QStringRef& contextInstr)
{
if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay"))
return;
if (contextInstr.startsWith(QLatin1String("#pop!"))) {
++m_popCount;
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 {
m_contextName = contextInstr.toString();
}
}
void ContextSwitch::resolve(const Definition &def)
{
auto d = def;
if (!m_defName.isEmpty()) {
d = DefinitionData::get(def)->repo->definitionForName(m_defName);
auto data = DefinitionData::get(d);
data->load();
if (m_contextName.isEmpty())
m_context = data->initialContext();
}
if (!m_contextName.isEmpty()) {
m_context = DefinitionData::get(d)->contextByName(m_contextName);
if (!m_context)
qCWarning(Log) << "cannot find context" << m_contextName << "in" << def.name();
}
}

View File

@@ -0,0 +1,56 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_CONTEXTSWITCH_P_H
#define KSYNTAXHIGHLIGHTING_CONTEXTSWITCH_P_H
#include <QString>
namespace KSyntaxHighlighting {
class Context;
class Definition;
class ContextSwitch
{
public:
ContextSwitch() = default;
~ContextSwitch() = default;
bool isStay() const;
int popCount() const;
Context* context() const;
void parse(const QStringRef &contextInstr);
void resolve(const Definition &def);
private:
QString m_defName;
QString m_contextName;
Context *m_context = nullptr;
int m_popCount = 0;
};
}
#endif // KSYNTAXHIGHLIGHTING_CONTEXTSWITCH_P_H

View File

@@ -0,0 +1,798 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Copyright (C) 2018 Dominik Haumann <dhaumann@kde.org>
Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "definition.h"
#include "definition_p.h"
#include "definitionref_p.h"
#include "context_p.h"
#include "format.h"
#include "format_p.h"
#include "repository_p.h"
#include "rule_p.h"
#include "ksyntaxhighlighting_logging.h"
#include "ksyntaxhighlighting_version.h"
#include "xml_p.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QHash>
#include <QJsonObject>
#include <QStringList>
#include <QVector>
#include <QXmlStreamReader>
#include <algorithm>
using namespace KSyntaxHighlighting;
DefinitionData::DefinitionData()
: wordDelimiters(QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~")) // must be sorted!
, wordWrapDelimiters(wordDelimiters)
{
}
DefinitionData::~DefinitionData()
{
qDeleteAll(contexts);
}
DefinitionData* DefinitionData::get(const Definition &def)
{
return def.d.get();
}
Definition::Definition() :
d(new DefinitionData)
{
}
Definition::Definition(const Definition &other) :
d(other.d)
{
d->q = *this;
}
Definition::Definition(const std::shared_ptr<DefinitionData> &dd) :
d(dd)
{
}
Definition::~Definition()
{
}
Definition& Definition::operator=(const Definition &rhs)
{
d = rhs.d;
return *this;
}
bool Definition::operator==(const Definition &other) const
{
return d->fileName == other.d->fileName;
}
bool Definition::operator!=(const Definition& other) const
{
return d->fileName != other.d->fileName;
}
bool Definition::isValid() const
{
return d->repo && !d->fileName.isEmpty() && !d->name.isEmpty();
}
QString Definition::filePath() const
{
return d->fileName;
}
QString Definition::name() const
{
return d->name;
}
QString Definition::translatedName() const
{
return QCoreApplication::instance()->translate("Language", d->name.toUtf8().constData());
}
QString Definition::section() const
{
return d->section;
}
QString Definition::translatedSection() const
{
return QCoreApplication::instance()->translate("Language Section", d->section.toUtf8().constData());
}
QVector<QString> Definition::mimeTypes() const
{
return d->mimetypes;
}
QVector<QString> Definition::extensions() const
{
return d->extensions;
}
int Definition::version() const
{
return d->version;
}
int Definition::priority() const
{
return d->priority;
}
bool Definition::isHidden() const
{
return d->hidden;
}
QString Definition::style() const
{
return d->style;
}
QString Definition::indenter() const
{
return d->indenter;
}
QString Definition::author() const
{
return d->author;
}
QString Definition::license() const
{
return d->license;
}
bool Definition::isWordDelimiter(QChar c) const
{
d->load();
return d->isWordDelimiter(c);
}
bool Definition::isWordWrapDelimiter(QChar c) const
{
d->load();
return std::binary_search(d->wordWrapDelimiters.constBegin(), d->wordWrapDelimiters.constEnd(), c);
}
bool Definition::foldingEnabled() const
{
d->load();
if (d->hasFoldingRegions || indentationBasedFoldingEnabled()) {
return true;
}
// check included definitions
const auto defs = includedDefinitions();
for (const auto &def : defs) {
if (def.foldingEnabled()) {
d->hasFoldingRegions = true;
break;
}
}
return d->hasFoldingRegions;
}
bool Definition::indentationBasedFoldingEnabled() const
{
d->load();
return d->indentationBasedFolding;
}
QStringList Definition::foldingIgnoreList() const
{
d->load();
return d->foldingIgnoreList;
}
QStringList Definition::keywordLists() const
{
d->load();
return d->keywordLists.keys();
}
QStringList Definition::keywordList(const QString& name) const
{
d->load();
const auto list = d->keywordList(name);
return list ? list->keywords() : QStringList();
}
QVector<Format> Definition::formats() const
{
d->load();
// sort formats so that the order matches the order of the itemDatas in the xml files.
auto formatList = QVector<Format>::fromList(d->formats.values());
std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format & lhs, const KSyntaxHighlighting::Format & rhs){
return lhs.id() < rhs.id();
});
return formatList;
}
QVector<Definition> Definition::includedDefinitions() const
{
d->load();
// init worklist and result used as guard with this definition
QVector<Definition> queue{*this};
QVector<Definition> definitions{*this};
while (!queue.isEmpty()) {
// Iterate all context rules to find associated Definitions. This will
// automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch.
const auto definition = queue.takeLast();
for (const auto & context : qAsConst(definition.d->contexts)) {
// handle context switch attributes of this context itself
for (const auto switchContext : {context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) {
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
definitions.pop_front();
return definitions;
}
QString Definition::singleLineCommentMarker() const
{
d->load();
return d->singleLineCommentMarker;
}
CommentPosition Definition::singleLineCommentPosition() const
{
d->load();
return d->singleLineCommentPosition;
}
QPair<QString, QString> Definition::multiLineCommentMarker() const
{
d->load();
return { d->multiLineCommentStartMarker, d->multiLineCommentEndMarker };
}
QVector<QPair<QChar, QString>> Definition::characterEncodings() const
{
d->load();
return d->characterEncodings;
}
Context* DefinitionData::initialContext() const
{
Q_ASSERT(!contexts.isEmpty());
return contexts.first();
}
Context* DefinitionData::contextByName(const QString& name) const
{
foreach (auto context, contexts) {
if (context->name() == name)
return context;
}
return nullptr;
}
KeywordList *DefinitionData::keywordList(const QString& name)
{
auto it = keywordLists.find(name);
return (it == keywordLists.end()) ? nullptr : &it.value();
}
bool DefinitionData::isWordDelimiter(QChar c) const
{
return std::binary_search(wordDelimiters.constBegin(), wordDelimiters.constEnd(), c);
}
Format DefinitionData::formatByName(const QString& name) const
{
const auto it = formats.constFind(name);
if (it != formats.constEnd())
return it.value();
return Format();
}
bool DefinitionData::isLoaded() const
{
return !contexts.isEmpty();
}
bool DefinitionData::load()
{
if (fileName.isEmpty())
return false;
if (isLoaded())
return true;
QFile file(fileName);
if (!file.open(QFile::ReadOnly))
return false;
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
const auto token = reader.readNext();
if (token != QXmlStreamReader::StartElement)
continue;
if (reader.name() == QLatin1String("highlighting"))
loadHighlighting(reader);
else if (reader.name() == QLatin1String("general"))
loadGeneral(reader);
}
for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it)
(*it).setCaseSensitivity(caseSensitive);
foreach (auto context, contexts) {
context->resolveContexts();
context->resolveIncludes();
context->resolveAttributeFormat();
}
Q_ASSERT(std::is_sorted(wordDelimiters.constBegin(), wordDelimiters.constEnd()));
return true;
}
void DefinitionData::clear()
{
// keep only name and repo, so we can re-lookup to make references persist over repo reloads
keywordLists.clear();
qDeleteAll(contexts);
contexts.clear();
formats.clear();
fileName.clear();
section.clear();
style.clear();
indenter.clear();
author.clear();
license.clear();
mimetypes.clear();
extensions.clear();
wordDelimiters = QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~"); // must be sorted!
wordWrapDelimiters = wordDelimiters;
caseSensitive = Qt::CaseSensitive;
version = 0.0f;
priority = 0;
hidden = false;
}
bool DefinitionData::loadMetaData(const QString& definitionFileName)
{
fileName = definitionFileName;
QFile file(definitionFileName);
if (!file.open(QFile::ReadOnly))
return false;
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
const auto token = reader.readNext();
if (token != QXmlStreamReader::StartElement)
continue;
if (reader.name() == QLatin1String("language")) {
return loadLanguage(reader);
}
}
return false;
}
bool DefinitionData::loadMetaData(const QString &file, const QJsonObject &obj)
{
name = obj.value(QLatin1String("name")).toString();
section = obj.value(QLatin1String("section")).toString();
version = obj.value(QLatin1String("version")).toInt();
priority = obj.value(QLatin1String("priority")).toInt();
style = obj.value(QLatin1String("style")).toString();
author = obj.value(QLatin1String("author")).toString();
license = obj.value(QLatin1String("license")).toString();
indenter = obj.value(QLatin1String("indenter")).toString();
hidden = obj.value(QLatin1String("hidden")).toBool();
fileName = file;
const auto exts = obj.value(QLatin1String("extensions")).toString();
foreach (const auto &ext, exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
extensions.push_back(ext);
const auto mts = obj.value(QLatin1String("mimetype")).toString();
foreach (const auto &mt, mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
mimetypes.push_back(mt);
return true;
}
bool DefinitionData::loadLanguage(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("language"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
if (!checkKateVersion(reader.attributes().value(QStringLiteral("kateversion"))))
return false;
name = reader.attributes().value(QStringLiteral("name")).toString();
section = reader.attributes().value(QStringLiteral("section")).toString();
// toFloat instead of toInt for backward compatibility with old Kate files
version = reader.attributes().value(QStringLiteral("version")).toFloat();
priority = reader.attributes().value(QStringLiteral("priority")).toInt();
hidden = Xml::attrToBool(reader.attributes().value(QStringLiteral("hidden")));
style = reader.attributes().value(QStringLiteral("style")).toString();
indenter = reader.attributes().value(QStringLiteral("indenter")).toString();
author = reader.attributes().value(QStringLiteral("author")).toString();
license = reader.attributes().value(QStringLiteral("license")).toString();
const auto exts = reader.attributes().value(QStringLiteral("extensions")).toString();
foreach (const auto &ext, exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
extensions.push_back(ext);
const auto mts = reader.attributes().value(QStringLiteral("mimetype")).toString();
foreach (const auto &mt, mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
mimetypes.push_back(mt);
if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
return true;
}
void DefinitionData::loadHighlighting(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("highlighting"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
if (reader.name() == QLatin1String("list")) {
KeywordList keywords;
keywords.load(reader);
keywordLists.insert(keywords.name(), keywords);
} else if (reader.name() == QLatin1String("contexts")) {
loadContexts(reader);
reader.readNext();
} else if (reader.name() == QLatin1String("itemDatas")) {
loadItemData(reader);
} else {
reader.readNext();
}
break;
case QXmlStreamReader::EndElement:
return;
default:
reader.readNext();
break;
}
}
}
void DefinitionData::loadContexts(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("contexts"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
if (reader.name() == QLatin1String("context")) {
auto context = new Context;
context->setDefinition(q);
context->load(reader);
contexts.push_back(context);
}
reader.readNext();
break;
case QXmlStreamReader::EndElement:
return;
default:
reader.readNext();
break;
}
}
}
void DefinitionData::loadItemData(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("itemDatas"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
if (reader.name() == QLatin1String("itemData")) {
Format f;
auto formatData = FormatPrivate::detachAndGet(f);
formatData->definition = q;
formatData->load(reader);
formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
formats.insert(f.name(), f);
reader.readNext();
}
reader.readNext();
break;
case QXmlStreamReader::EndElement:
return;
default:
reader.readNext();
break;
}
}
}
void DefinitionData::loadGeneral(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("general"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
reader.readNext();
// reference counter to count XML child elements, to not return too early
int elementRefCounter = 1;
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
++elementRefCounter;
if (reader.name() == QLatin1String("keywords")) {
if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
// adapt sorted wordDelimiters
wordDelimiters += reader.attributes().value(QStringLiteral("additionalDeliminator"));
std::sort(wordDelimiters.begin(), wordDelimiters.end());
auto it = std::unique(wordDelimiters.begin(), wordDelimiters.end());
wordDelimiters.truncate(std::distance(wordDelimiters.begin(), it));
foreach (const auto c, reader.attributes().value(QLatin1String("weakDeliminator")))
wordDelimiters.remove(c);
// adaptWordWrapDelimiters, and sort
wordWrapDelimiters = reader.attributes().value(QStringLiteral("wordWrapDeliminator")).toString();
std::sort(wordWrapDelimiters.begin(), wordWrapDelimiters.end());
if (wordWrapDelimiters.isEmpty())
wordWrapDelimiters = wordDelimiters;
} else if (reader.name() == QLatin1String("folding")) {
if (reader.attributes().hasAttribute(QStringLiteral("indentationsensitive")))
indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("indentationsensitive")));
} else if (reader.name() == QLatin1String("emptyLines")) {
loadFoldingIgnoreList(reader);
} else if (reader.name() == QLatin1String("comments")) {
loadComments(reader);
} else if (reader.name() == QLatin1String("spellchecking")) {
loadSpellchecking(reader);
} else {
reader.skipCurrentElement();
}
reader.readNext();
break;
case QXmlStreamReader::EndElement:
--elementRefCounter;
if (elementRefCounter == 0)
return;
reader.readNext();
break;
default:
reader.readNext();
break;
}
}
}
void DefinitionData::loadComments(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("comments"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
reader.readNext();
// reference counter to count XML child elements, to not return too early
int elementRefCounter = 1;
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
++elementRefCounter;
if (reader.name() == QLatin1String("comment")) {
const bool isSingleLine = reader.attributes().value(QStringLiteral("name")) == QStringLiteral("singleLine");
if (isSingleLine) {
singleLineCommentMarker = reader.attributes().value(QStringLiteral("start")).toString();
const bool afterWhiteSpace = reader.attributes().value(QStringLiteral("position")).toString() == QStringLiteral("afterwhitespace");
singleLineCommentPosition = afterWhiteSpace ? CommentPosition::AfterWhitespace : CommentPosition::StartOfLine;
} else {
multiLineCommentStartMarker = reader.attributes().value(QStringLiteral("start")).toString();
multiLineCommentEndMarker = reader.attributes().value(QStringLiteral("end")).toString();
}
}
reader.readNext();
break;
case QXmlStreamReader::EndElement:
--elementRefCounter;
if (elementRefCounter == 0)
return;
reader.readNext();
break;
default:
reader.readNext();
break;
}
}
}
void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("emptyLines"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
reader.readNext();
// reference counter to count XML child elements, to not return too early
int elementRefCounter = 1;
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
++elementRefCounter;
if (reader.name() == QLatin1String("emptyLine")) {
foldingIgnoreList << reader.attributes().value(QStringLiteral("regexpr")).toString();
}
reader.readNext();
break;
case QXmlStreamReader::EndElement:
--elementRefCounter;
if (elementRefCounter == 0)
return;
reader.readNext();
break;
default:
reader.readNext();
break;
}
}
}
void DefinitionData::loadSpellchecking(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("spellchecking"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
reader.readNext();
// reference counter to count XML child elements, to not return too early
int elementRefCounter = 1;
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
++elementRefCounter;
if (reader.name() == QLatin1String("encoding")) {
const auto charRef = reader.attributes().value(QStringLiteral("char"));
if (!charRef.isEmpty()) {
const auto str = reader.attributes().value(QStringLiteral("string")).toString();
characterEncodings.push_back({ charRef[0], str });
}
}
reader.readNext();
break;
case QXmlStreamReader::EndElement:
--elementRefCounter;
if (elementRefCounter == 0)
return;
reader.readNext();
break;
default:
reader.readNext();
break;
}
}
}
bool DefinitionData::checkKateVersion(const QStringRef& verStr)
{
const auto idx = verStr.indexOf(QLatin1Char('.'));
if (idx <= 0) {
qCWarning(Log) << "Skipping" << fileName << "due to having no valid kateversion attribute:" << verStr;
return false;
}
const auto major = verStr.left(idx).toInt();
const auto minor = verStr.mid(idx + 1).toInt();
if (major > SyntaxHighlighting_VERSION_MAJOR || (major == SyntaxHighlighting_VERSION_MAJOR && minor > SyntaxHighlighting_VERSION_MINOR)) {
qCWarning(Log) << "Skipping" << fileName << "due to being too new, version:" << verStr;
return false;
}
return true;
}
quint16 DefinitionData::foldingRegionId(const QString &foldName)
{
hasFoldingRegions = true;
return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName);
}
DefinitionRef::DefinitionRef()
{
}
DefinitionRef::DefinitionRef(const Definition &def) :
d(def.d)
{
}
DefinitionRef::~DefinitionRef()
{
}
DefinitionRef& DefinitionRef::operator=(const Definition &def)
{
d = def.d;
return *this;
}
Definition DefinitionRef::definition() const
{
if (!d.expired())
return Definition(d.lock());
return Definition();
}
bool DefinitionRef::operator==(const DefinitionRef &other) const
{
if (d.expired() != other.d.expired()) {
return false;
}
return d.expired() || d.lock().get() == other.d.lock().get();
}

View File

@@ -0,0 +1,400 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_DEFINITION_H
#define KSYNTAXHIGHLIGHTING_DEFINITION_H
#include "ksyntaxhighlighting_export.h"
#include <QTypeInfo>
#include <QPair>
#include <memory>
QT_BEGIN_NAMESPACE
class QChar;
class QString;
class QStringList;
template <typename T> class QVector;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class Context;
class Format;
class KeywordList;
class DefinitionData;
/**
* Defines the insert position when commenting code.
* @since 5.50
* @see Definition::singleLineCommentPosition()
*/
enum class CommentPosition
{
//! The comment marker is inserted at the beginning of a line at column 0
StartOfLine = 0,
//! The comment marker is inserted after leading whitespaces right befire
//! the first non-whitespace character.
AfterWhitespace
};
/**
* Represents a syntax definition.
*
* @section def_intro Introduction to Definitions
*
* A Definition is the short term for a syntax highlighting definition. It
* typically is defined in terms of an XML syntax highlighting file, containing
* all information about a particular syntax highlighting. This includes the
* highlighting of keywords, information about code folding regions, and
* indentation preferences.
*
* @section def_info General Header Data
*
* Each Definition contains a non-translated unique name() and a section().
* In addition, for putting this information e.g. into menus, the functions
* translatedName() and translatedSection() are provided. However, if isHidden()
* returns @e true, the Definition should not be visible in the UI. The location
* of the Definition can be obtained through filePath(), which either is the
* location on disk or a path to a compiled-in Qt resource.
*
* The supported files of a Definition are defined by the list of extensions(),
* and additionally by the list of mimeTypes(). Note, that extensions() returns
* wildcards that need to be matched against the filename of the file that
* requires highlighting. If multiple Definition%s match the file, then the one
* with higher priority() wins.
*
* @section def_metadata Advanced Definition Data
*
* Advanced text editors such as Kate require additional information from a
* Definition. For instance, foldingEnabled() defines whether a Definition has
* code folding regions that can be shown in a code folding pane. Or
* singleLineCommentMarker() and multiLineCommentMarker() provide comment
* markers that can be used for commenting/uncommenting code. Similarly,
* formats() returns a list of Format items defined by this Definition (which
* equal the itemDatas of a highlighing definition file). includedDefinitions()
* returns a list of all included Definition%s referenced by this Definition via
* the rule IncludeRules, which is useful for displaying all Format items for
* color configuration in the user interface.
*
* @see Repository
* @since 5.28
*/
class KSYNTAXHIGHLIGHTING_EXPORT Definition
{
public:
/**
* Default constructor, creating an empty (invalid) Definition instance.
* isValid() for this instance returns @e false.
*
* Use the Repository instead to obtain valid instances.
*/
Definition();
/**
* Copy constructor.
* Both this definition as well as @p other share the Definition data.
*/
Definition(const Definition &other);
/**
* Destructor.
*/
~Definition();
/**
* Assignment operator.
* Both this definition as well as @p rhs share the Definition data.
*/
Definition& operator=(const Definition &rhs);
/**
* Checks two definitions for equality.
*/
bool operator==(const Definition &other) const;
/**
* Checks two definitions for inequality.
*/
bool operator!=(const Definition &other) const;
/**
* @name General Header Data
*
* @{
*/
/**
* Checks whether this object refers to a valid syntax definition.
*/
bool isValid() const;
/**
* Returns the full path to the definition XML file containing
* the syntax definition. Note that this can be a path to QRC content.
*/
QString filePath() const;
/** Name of the syntax.
* Used for internal references, prefer translatedName() for display.
*/
QString name() const;
/**
* Translated name for display.
*/
QString translatedName() const;
/**
* The group this syntax definition belongs to.
* For display, consider translatedSection().
*/
QString section() const;
/**
* Translated group name for display.
*/
QString translatedSection() const;
/**
* Mime types associated with this syntax definition.
*/
QVector<QString> mimeTypes() const;
/**
* File extensions associated with this syntax definition.
* The returned list contains wildcards.
*/
QVector<QString> extensions() const;
/**
* Returns the definition version.
*/
int version() const;
/**
* Returns the definition priority.
* A Definition with higher priority wins over Definitions with lower priorities.
*/
int priority() const;
/**
* Returns @c true if this is an internal definition that should not be
* displayed to the user.
*/
bool isHidden() const;
/**
* Generalized language style, used for indentation.
*/
QString style() const;
/**
* Indentation style to be used for this syntax.
*/
QString indenter() const;
/**
* Name and email of the author of this syntax definition.
*/
QString author() const;
/**
* License of this syntax definition.
*/
QString license() const;
/**
* @}
*
* @name Advanced Definition Data
*/
/**
* Returns whether the character @p c is a word delimiter.
* A delimiter defines whether a characters is a word boundary. Internally,
* delimiters are used for matching keyword lists. As example, typically the
* dot '.' is a word delimiter. However, if you have a keyword in a keyword
* list that contains a dot, you have to add the dot to the
* @e weakDeliminator attribute of the @e general section in your
* highlighting definition. Similarly, sometimes additional delimiters are
* required, which can be specified in @e additionalDeliminator.
*
* Checking whether a character is a delimiter is useful for instance if
* text is selected with double click. Typically, the whole word should be
* selected in this case. Similarly to the example above, the dot '.'
* usually acts as word delimiter. However, using this function you can
* implement text selection in such a way that keyword lists are correctly
* selected.
*
* @note By default, the list of delimiters contains the following
* characters: \\t !%&()*+,-./:;<=>?[\\]^{|}~
*
* @since 5.50
* @see isWordWrapDelimiter()
*/
bool isWordDelimiter(QChar c) const;
/**
* Returns whether it is safe to break a line at before the character @c.
* This is useful when wrapping a line e.g. by applying static word wrap.
*
* As example, consider the LaTeX code
* @code
* \command1\command2
* @endcode
* Applying static word wrap could lead to the following code:
* @code
* \command1\
* command2
* @endcode
* command2 without a leading backslash is invalid in LaTeX. If '\\' is set
* as word wrap delimiter, isWordWrapDelimiter('\\') then returns true,
* meaning that it is safe to break the line before @c. The resulting code
* then would be
* @code
* \command1
* \command2
* @endcode
*
* @note By default, the word wrap delimiters are equal to the word
* delimiters in isWordDelimiter().
*
* @since 5.50
* @see isWordDelimiter()
*/
bool isWordWrapDelimiter(QChar c) const;
/**
* Returns whether the highlighting supports code folding.
* Code folding is supported either if the highlighting defines code folding
* regions or if indentationBasedFoldingEnabled() returns @e true.
* @since 5.50
* @see indentationBasedFoldingEnabled()
*/
bool foldingEnabled() const;
/**
* Returns whether indentation-based folding is enabled.
* An example for indentation-based folding is Python.
* When indentation-based folding is enabled, make sure to also check
* foldingIgnoreList() for lines that should be treated as empty.
*
* @see foldingIgnoreList(), State::indentationBasedFoldingEnabled()
*/
bool indentationBasedFoldingEnabled() const;
/**
* If indentationBasedFoldingEnabled() returns @c true, this function returns
* a list of regular expressions that represent empty lines. That is, all
* lines matching entirely one of the regular expressions should be treated
* as empty lines when calculating the indentation-based folding ranges.
*
* @note This list is only of relevance, if indentationBasedFoldingEnabled()
* returns @c true.
*
* @see indentationBasedFoldingEnabled()
*/
QStringList foldingIgnoreList() const;
/**
* Returns the section names of keywords.
* @since 5.49
* @see keywordList()
*/
QStringList keywordLists() const;
/**
* Returns the list of keywords for the keyword list @p name.
* @since 5.49
* @see keywordLists()
*/
QStringList keywordList(const QString& name) const;
/**
* Returns a list of all Format items used by this definition.
* The order of the Format items equals the order of the itemDatas in the xml file.
* @since 5.49
*/
QVector<Format> formats() const;
/**
* Returns a list of Definitions that are referenced with the IncludeRules rule.
* The returned list does not include this Definition. In case no other
* Definitions are referenced via IncludeRules, the returned list is empty.
*
* @since 5.49
*/
QVector<Definition> includedDefinitions() const;
/**
* Returns the marker that starts a single line comment.
* For instance, in C++ the single line comment marker is "//".
* @since 5.50
* @see singleLineCommentPosition();
*/
QString singleLineCommentMarker() const;
/**
* Returns the insert position of the comment marker for sinle line
* comments.
* @since 5.50
* @see singleLineCommentMarker();
*/
CommentPosition singleLineCommentPosition() const;
/**
* Returns the markers that start and end multiline comments.
* For instance, in XML this is defined as "<!--" and "-->".
* @since 5.50
*/
QPair<QString, QString> multiLineCommentMarker() const;
/**
* Returns a list of character/string mapping that can be used for spell
* checking. This is useful for instance when spell checking LaTeX, where
* the string \"{A} represents the character Ä.
* @since 5.50
*/
QVector<QPair<QChar, QString>> characterEncodings() const;
/**
* @}
*/
private:
friend class DefinitionData;
friend class DefinitionRef;
explicit Definition(const std::shared_ptr<DefinitionData> &dd);
std::shared_ptr<DefinitionData> d;
};
}
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Definition, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif

View File

@@ -0,0 +1,111 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_DEFINITION_P_H
#define KSYNTAXHIGHLIGHTING_DEFINITION_P_H
#include "definitionref_p.h"
#include "definition.h"
#include <QHash>
#include <QString>
#include <QVector>
QT_BEGIN_NAMESPACE
class QXmlStreamReader;
class QJsonObject;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class Repository;
class DefinitionData
{
public:
DefinitionData();
~DefinitionData();
static DefinitionData* get(const Definition &def);
bool isLoaded() const;
bool loadMetaData(const QString &definitionFileName);
bool loadMetaData(const QString &fileName, const QJsonObject &obj);
void clear();
bool load();
bool loadLanguage(QXmlStreamReader &reader);
void loadHighlighting(QXmlStreamReader &reader);
void loadContexts(QXmlStreamReader &reader);
void loadItemData(QXmlStreamReader &reader);
void loadGeneral(QXmlStreamReader &reader);
void loadComments(QXmlStreamReader &reader);
void loadFoldingIgnoreList(QXmlStreamReader &reader);
void loadSpellchecking(QXmlStreamReader &reader);
bool checkKateVersion(const QStringRef &verStr);
KeywordList *keywordList(const QString &name);
bool isWordDelimiter(QChar c) const;
Context* initialContext() const;
Context* contextByName(const QString &name) const;
Format formatByName(const QString &name) const;
quint16 foldingRegionId(const QString &foldName);
DefinitionRef q;
Repository *repo = nullptr;
QHash<QString, KeywordList> keywordLists;
QVector<Context*> contexts;
QHash<QString, Format> formats;
QString wordDelimiters;
QString wordWrapDelimiters;
bool hasFoldingRegions = false;
bool indentationBasedFolding = false;
QStringList foldingIgnoreList;
QString singleLineCommentMarker;
CommentPosition singleLineCommentPosition = CommentPosition::StartOfLine;
QString multiLineCommentStartMarker;
QString multiLineCommentEndMarker;
QVector<QPair<QChar, QString>> characterEncodings;
QString fileName;
QString name = QStringLiteral(QT_TRANSLATE_NOOP("Syntax highlighting", "None"));
QString section;
QString style;
QString indenter;
QString author;
QString license;
QVector<QString> mimetypes;
QVector<QString> extensions;
Qt::CaseSensitivity caseSensitive = Qt::CaseSensitive;
int version = 0;
int priority = 0;
bool hidden = false;
};
}
#endif

View File

@@ -0,0 +1,193 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "definitiondownloader.h"
#include "definition.h"
#include "repository.h"
#include "ksyntaxhighlighting_logging.h"
#include "ksyntaxhighlighting_version.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QStandardPaths>
#include <QTimer>
#include <QXmlStreamReader>
using namespace KSyntaxHighlighting;
class KSyntaxHighlighting::DefinitionDownloaderPrivate
{
public:
DefinitionDownloader *q;
Repository *repo;
QNetworkAccessManager *nam;
QString downloadLocation;
int pendingDownloads;
bool needsReload;
void definitionListDownloadFinished(QNetworkReply *reply);
void updateDefinition(QXmlStreamReader &parser);
void downloadDefinition(const QUrl &url);
void downloadDefinitionFinished(QNetworkReply *reply);
void checkDone();
};
void DefinitionDownloaderPrivate::definitionListDownloadFinished(QNetworkReply *reply)
{
if (reply->error() != QNetworkReply::NoError) {
qCWarning(Log) << reply->error();
emit q->done(); // TODO return error
return;
}
QXmlStreamReader parser(reply);
while (!parser.atEnd()) {
switch (parser.readNext()) {
case QXmlStreamReader::StartElement:
if (parser.name() == QLatin1String("Definition"))
updateDefinition(parser);
break;
default:
break;
}
}
if (pendingDownloads == 0)
emit q->informationMessage(QObject::tr("All syntax definitions are up-to-date."));
checkDone();
}
void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser)
{
const auto name = parser.attributes().value(QLatin1String("name"));
if (name.isEmpty())
return;
auto localDef = repo->definitionForName(name.toString());
if (!localDef.isValid()) {
emit q->informationMessage(QObject::tr("Downloading new syntax definition for '%1'...").arg(name.toString()));
downloadDefinition(QUrl(parser.attributes().value(QLatin1String("url")).toString()));
return;
}
const auto version = parser.attributes().value(QLatin1String("version"));
if (localDef.version() < version.toFloat()) {
emit q->informationMessage(QObject::tr("Updating syntax definition for '%1' to version %2...").arg(name.toString(), version.toString()));
downloadDefinition(QUrl(parser.attributes().value(QLatin1String("url")).toString()));
}
}
void DefinitionDownloaderPrivate::downloadDefinition(const QUrl& downloadUrl)
{
if (!downloadUrl.isValid())
return;
auto url = downloadUrl;
if (url.scheme() == QLatin1String("http"))
url.setScheme(QStringLiteral("https"));
QNetworkRequest req(url);
auto reply = nam->get(req);
QObject::connect(reply, &QNetworkReply::finished, q, [this, reply]() {
downloadDefinitionFinished(reply);
});
++pendingDownloads;
needsReload = true;
}
void DefinitionDownloaderPrivate::downloadDefinitionFinished(QNetworkReply *reply)
{
--pendingDownloads;
if (reply->error() != QNetworkReply::NoError) {
qCWarning(Log) << "Failed to download definition file" << reply->url() << reply->error();
checkDone();
return;
}
// handle redirects
// needs to be done manually, download server redirects to unsafe http links
const auto redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (!redirectUrl.isEmpty()) {
downloadDefinition(reply->url().resolved(redirectUrl));
checkDone();
return;
}
QFile file(downloadLocation + QLatin1Char('/') + reply->url().fileName());
if (!file.open(QFile::WriteOnly)) {
qCWarning(Log) << "Failed to open" << file.fileName() << file.error();
} else {
file.write(reply->readAll());
}
checkDone();
}
void DefinitionDownloaderPrivate::checkDone()
{
if (pendingDownloads == 0) {
if (needsReload)
repo->reload();
emit QTimer::singleShot(0, q, &DefinitionDownloader::done);
}
}
DefinitionDownloader::DefinitionDownloader(Repository *repo, QObject *parent)
: QObject(parent)
, d(new DefinitionDownloaderPrivate())
{
Q_ASSERT(repo);
d->q = this;
d->repo = repo;
d->nam = new QNetworkAccessManager(this);
d->pendingDownloads = 0;
d->needsReload = false;
d->downloadLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/org.kde.syntax-highlighting/syntax");
QDir().mkpath(d->downloadLocation);
Q_ASSERT(QFile::exists(d->downloadLocation));
}
DefinitionDownloader::~DefinitionDownloader()
{
}
void DefinitionDownloader::start()
{
const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-")
+ QString::number(SyntaxHighlighting_VERSION_MAJOR)
+ QLatin1Char('.')
+ QString::number(SyntaxHighlighting_VERSION_MINOR)
+ QLatin1String(".xml");
auto req = QNetworkRequest(QUrl(url));
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
auto reply = d->nam->get(req);
QObject::connect(reply, &QNetworkReply::finished, this, [=]() {
d->definitionListDownloadFinished(reply);
});
}

View File

@@ -0,0 +1,113 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_DEFINITIONDOWNLOADER_H
#define KSYNTAXHIGHLIGHTING_DEFINITIONDOWNLOADER_H
#include "ksyntaxhighlighting_export.h"
#include <QObject>
#include <memory>
namespace KSyntaxHighlighting {
class DefinitionDownloaderPrivate;
class Repository;
/**
* Helper class to download definition file updates.
*
* With the DefinitionDownloader you can download new and update existing
* syntax highlighting definition files (xml files).
*
* An example that updates the highlighting Definition%s and prints the current
* update progress to the console may look as follows:
*
* @code
* auto downloader = new DefinitionDownloader(repo); // repo is a pointer to a Repository
*
* // print update progress to console
* QObject::connect(downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) {
* std::cout << qPrintable(msg) << std::endl;
* });
*
* // connect to signal done to delete the downloader later
* QObject::connect(downloader, &DefinitionDownloader::done,
* downloader, &DefinitionDownloader::deleteLater);
* downloader->start();
* @endcode
*
* @see Repository, Definition
* @since 5.28
*/
class KSYNTAXHIGHLIGHTING_EXPORT DefinitionDownloader : public QObject
{
Q_OBJECT
public:
/**
* Constructor.
* The Repository @p repo is used as reference to compare the versions of
* the existing Definition%s with the ones that are available online.
*
* Optionally, @p parent is a pointer to the owner of this instance.
*/
explicit DefinitionDownloader(Repository *repo, QObject *parent = nullptr);
/**
* Destructor.
*/
~DefinitionDownloader();
/**
* Starts the update procedure.
* Once no more updates are available (i.e. either the local definition files
* are up-to-date, or all updates have been downloaded), the signal done()
* is emitted.
*
* During the update process, the signal informationMessage() can be used
* to display the current update progress to the user.
*
* @see done(), informationMessage()
*/
void start();
Q_SIGNALS:
/**
* Prints the information about the current state of the definition files.
* If all files are up-to-date, this signal is emitted informing you that
* all highlighting files are up-to-date. If there are updates, this signal
* is emitted for each update being downloaded.
*/
void informationMessage(const QString &msg);
/**
* This signal is emitted when there are no pending downloads anymore.
*/
void done();
private:
std::unique_ptr<DefinitionDownloaderPrivate> d;
};
}
#endif // KSYNTAXHIGHLIGHTING_DEFINITIONDOWNLOADER_H

View File

@@ -0,0 +1,74 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
#define KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
#include <memory>
namespace KSyntaxHighlighting {
class Definition;
class DefinitionData;
class DefinitionPrivate;
/** Weak reference for Definition instances.
*
* This must be used when holding Definition instances
* in objects hold directly or indirectly by Definition
* to avoid reference count loops and thus memory leaks.
*
* @internal
*/
class DefinitionRef
{
public:
DefinitionRef();
explicit DefinitionRef(const Definition &def);
~DefinitionRef();
DefinitionRef& operator=(const Definition &def);
Definition definition() const;
/**
* Checks two definition references for equality.
*/
bool operator==(const DefinitionRef &other) const;
/**
* Checks two definition references for inequality.
*/
bool operator!=(const DefinitionRef &other) const
{
return !(*this == other);
}
private:
friend class DefinitionData;
std::weak_ptr<DefinitionData> d;
};
}
#endif

View File

@@ -0,0 +1,60 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "foldingregion.h"
using namespace KSyntaxHighlighting;
static_assert(sizeof(FoldingRegion) == 2, "FoldingRegion is size-sensitive to frequent use in KTextEditor!");
FoldingRegion::FoldingRegion() :
m_type(None),
m_id(0)
{
}
FoldingRegion::FoldingRegion(Type type, quint16 id) :
m_type(type),
m_id(id)
{
}
bool FoldingRegion::operator==(const FoldingRegion &other) const
{
return m_id == other.m_id && m_type == other.m_type;
}
bool FoldingRegion::isValid() const
{
return type() != None;
}
quint16 FoldingRegion::id() const
{
return m_id;
}
FoldingRegion::Type FoldingRegion::type() const
{
return static_cast<FoldingRegion::Type>(m_type);
}

View File

@@ -0,0 +1,108 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_FOLDINGREGION_H
#define KSYNTAXHIGHLIGHTING_FOLDINGREGION_H
#include "ksyntaxhighlighting_export.h"
#include <QTypeInfo>
namespace KSyntaxHighlighting {
/** Represents a begin or end of a folding region.
* @since 5.28 */
class KSYNTAXHIGHLIGHTING_EXPORT FoldingRegion
{
public:
/**
* Defines whether a FoldingRegion starts or ends a folding region.
*/
enum Type {
//! Used internally as indicator for invalid FoldingRegion%s.
None,
//! Indicates the start of a FoldingRegion.
Begin,
//! Indicates the end of a FoldingRegion.
End
};
/**
* Constructs an invalid folding region, meaning that isValid() returns @e false.
* To obtain valid instances, see AbstractHighlighter::applyFolding().
*/
FoldingRegion();
/** Compares two FoldingRegion instances for equality. */
bool operator==(const FoldingRegion &other) const;
/**
* Returns @c true if this is a valid folding region.
* A valid FoldingRegion is defined by a type() other than Type::None.
*
* @note The FoldingRegion%s passed in AbstractHighlighter::applyFolding()
* are always valid.
*/
bool isValid() const;
/**
* Returns a unique identifier for this folding region.
*
* As example, the C/C++ highlighter starts and ends a folding region for
* scopes, e.g.:
* \code
* void foo() { // '{' starts a folding region
* if (bar()) { // '{' starts a (nested) folding region
* } // '}' ends the (nested) folding region
* } // '}' ends the outer folding region
* \endcode
* In this example, all braces '{' and '}' have the same id(), meaning that
* if you want to find the matching closing region for the first opening
* brace, you need to do kind of a reference counting to find the correct
* closing brace.
*/
quint16 id() const;
/**
* Returns whether this is the begin or end of a region.
*
* @note The FoldingRegion%s passed in AbstractHighlighter::applyFolding()
* are always valid, i.e. either Type::Begin or Type::End.
*/
Type type() const;
private:
friend class Rule;
FoldingRegion(Type type, quint16 id);
quint16 m_type : 2;
quint16 m_id: 14;
};
}
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(KSyntaxHighlighting::FoldingRegion, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
#endif

View File

@@ -0,0 +1,264 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "format.h"
#include "format_p.h"
#include "definition.h"
#include "definitionref_p.h"
#include "textstyledata_p.h"
#include "themedata_p.h"
#include "xml_p.h"
#include <QColor>
#include <QDebug>
#include <QMetaEnum>
#include <QXmlStreamReader>
using namespace KSyntaxHighlighting;
static Theme::TextStyle stringToDefaultFormat(const QStringRef &str)
{
if (!str.startsWith(QLatin1String("ds")))
return Theme::Normal;
static const auto idx = Theme::staticMetaObject.indexOfEnumerator("TextStyle");
Q_ASSERT(idx >= 0);
const auto metaEnum = Theme::staticMetaObject.enumerator(idx);
bool ok = false;
const auto value = metaEnum.keyToValue(str.mid(2).toLatin1().constData(), &ok);
if (!ok || value < 0)
return Theme::Normal;
return static_cast<Theme::TextStyle>(value);
}
FormatPrivate* FormatPrivate::detachAndGet(Format &format)
{
format.d.detach();
return format.d.data();
}
TextStyleData FormatPrivate::styleOverride(const Theme &theme) const
{
const auto themeData = ThemeData::get(theme);
if (themeData)
return themeData->textStyleOverride(definition.definition().name(), name);
return TextStyleData();
}
static QExplicitlySharedDataPointer<FormatPrivate> &sharedDefaultPrivate()
{
static QExplicitlySharedDataPointer<FormatPrivate> def(new FormatPrivate);
return def;
}
Format::Format() : d(sharedDefaultPrivate())
{
}
Format::Format(const Format &other) :
d(other.d)
{
}
Format::~Format()
{
}
Format& Format::operator=(const Format& other)
{
d = other.d;
return *this;
}
bool Format::isValid() const
{
return !d->name.isEmpty();
}
QString Format::name() const
{
return d->name;
}
quint16 Format::id() const
{
return d->id;
}
Theme::TextStyle Format::textStyle() const
{
return d->defaultStyle;
}
bool Format::isDefaultTextStyle(const Theme &theme) const
{
return (!hasTextColor(theme))
&& (!hasBackgroundColor(theme))
&& (selectedTextColor(theme) == theme.selectedTextColor(Theme::Normal))
&& (selectedBackgroundColor(theme) == theme.selectedBackgroundColor(Theme::Normal))
&& (isBold(theme) == theme.isBold(Theme::Normal))
&& (isItalic(theme) == theme.isItalic(Theme::Normal))
&& (isUnderline(theme) == theme.isUnderline(Theme::Normal))
&& (isStrikeThrough(theme) == theme.isStrikeThrough(Theme::Normal));
}
bool Format::hasTextColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
return textColor(theme) != theme.textColor(Theme::Normal)
&& (d->style.textColor || theme.textColor(d->defaultStyle) || overrideStyle.textColor);
}
QColor Format::textColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.textColor)
return overrideStyle.textColor;
return d->style.textColor ? d->style.textColor : theme.textColor(d->defaultStyle);
}
QColor Format::selectedTextColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.selectedTextColor)
return overrideStyle.selectedTextColor;
return d->style.selectedTextColor ? d->style.selectedTextColor : theme.selectedTextColor(d->defaultStyle);
}
bool Format::hasBackgroundColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
return backgroundColor(theme) != theme.backgroundColor(Theme::Normal)
&& (d->style.backgroundColor || theme.backgroundColor(d->defaultStyle) || overrideStyle.backgroundColor);
}
QColor Format::backgroundColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.backgroundColor)
return overrideStyle.backgroundColor;
return d->style.backgroundColor ? d->style.backgroundColor : theme.backgroundColor(d->defaultStyle);
}
QColor Format::selectedBackgroundColor(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.selectedBackgroundColor)
return overrideStyle.selectedBackgroundColor;
return d->style.selectedBackgroundColor ? d->style.selectedBackgroundColor
: theme.selectedBackgroundColor(d->defaultStyle);
}
bool Format::isBold(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.hasBold)
return overrideStyle.bold;
return d->style.hasBold ? d->style.bold : theme.isBold(d->defaultStyle);
}
bool Format::isItalic(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.hasItalic)
return overrideStyle.italic;
return d->style.hasItalic ? d->style.italic : theme.isItalic(d->defaultStyle);
}
bool Format::isUnderline(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.hasUnderline)
return overrideStyle.underline;
return d->style.hasUnderline ? d->style.underline : theme.isUnderline(d->defaultStyle);
}
bool Format::isStrikeThrough(const Theme &theme) const
{
const auto overrideStyle = d->styleOverride(theme);
if (overrideStyle.hasStrikeThrough)
return overrideStyle.strikeThrough;
return d->style.hasStrikeThrough ? d->style.strikeThrough : theme.isStrikeThrough(d->defaultStyle);
}
bool Format::spellCheck() const
{
return d->spellCheck;
}
void FormatPrivate::load(QXmlStreamReader& reader)
{
name = reader.attributes().value(QStringLiteral("name")).toString();
defaultStyle = stringToDefaultFormat(reader.attributes().value(QStringLiteral("defStyleNum")));
QStringRef ref = reader.attributes().value(QStringLiteral("color"));
if (!ref.isEmpty()) {
style.textColor = QColor(ref.toString()).rgba();
}
ref = reader.attributes().value(QStringLiteral("selColor"));
if (!ref.isEmpty()) {
style.selectedTextColor = QColor(ref.toString()).rgba();
}
ref = reader.attributes().value(QStringLiteral("backgroundColor"));
if (!ref.isEmpty()) {
style.backgroundColor = QColor(ref.toString()).rgba();
}
ref = reader.attributes().value(QStringLiteral("selBackgroundColor"));
if (!ref.isEmpty()) {
style.selectedBackgroundColor = QColor(ref.toString()).rgba();
}
ref = reader.attributes().value(QStringLiteral("italic"));
if (!ref.isEmpty()) {
style.hasItalic = true;
style.italic = Xml::attrToBool(ref);
}
ref = reader.attributes().value(QStringLiteral("bold"));
if (!ref.isEmpty()) {
style.hasBold = true;
style.bold = Xml::attrToBool(ref);
}
ref = reader.attributes().value(QStringLiteral("underline"));
if (!ref.isEmpty()) {
style.hasUnderline = true;
style.underline = Xml::attrToBool(ref);
}
ref = reader.attributes().value(QStringLiteral("strikeOut"));
if (!ref.isEmpty()) {
style.hasStrikeThrough = true;
style.strikeThrough = Xml::attrToBool(ref);
}
ref = reader.attributes().value(QStringLiteral("spellChecking"));
if (!ref.isEmpty()) {
spellCheck = Xml::attrToBool(ref);
}
}

View File

@@ -0,0 +1,152 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_FORMAT_H
#define KSYNTAXHIGHLIGHTING_FORMAT_H
#include "ksyntaxhighlighting_export.h"
#include "theme.h"
#include <QExplicitlySharedDataPointer>
#include <QTypeInfo>
QT_BEGIN_NAMESPACE
class QColor;
class QString;
class QXmlStreamReader;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class DefinitionRef;
class FormatPrivate;
/** Describes the format to be used for a specific text fragment.
* The actual format used for displaying is merged from the format information
* in the syntax definition file, and a theme.
*
* @see Theme
* @since 5.28
*/
class KSYNTAXHIGHLIGHTING_EXPORT Format
{
public:
/** Creates an empty/invalid format. */
Format();
Format(const Format &other);
~Format();
Format& operator=(const Format &other);
/** Returns @c true if this is a valid format, ie. one that
* was read from a syntax definition file.
*/
bool isValid() const;
/** The name of this format as used in the syntax definition file. */
QString name() const;
/** Returns a unique identifier of this format.
* This is useful for efficient storing of formats in a text line. The
* identifier is unique per Repository instance, but will change when
* the repository is reloaded (which also invalidatess the corresponding
* Definition anyway).
*/
quint16 id() const;
/** Returns the underlying TextStyle of this Format.
* Every Theme::TextStyle is visually defined by a Theme. A Format uses one
* of the Theme::TextStyle%s and on top allows modifications such as setting
* a different foreground color etc.
* @see Theme::TextStyle
* @since 5.49
*/
Theme::TextStyle textStyle() const;
/** Returns @c true if the combination of this format and the theme @p theme
* do not change the default text format in any way.
* This is useful for output formats where changing formatting implies cost,
* and thus benefit from optimizing the default case of not having any format
* applied. If you make use of this, make sure to set the default text style
* to what the corresponding theme sets for Theme::Normal.
*/
bool isDefaultTextStyle(const Theme &theme) const;
/** Returns @c true if the combination of this format and the theme @p theme
* change the foreground color compared to the default format.
*/
bool hasTextColor(const Theme &theme) const;
/** Returns the foreground color of the combination of this format and the
* given theme.
*/
QColor textColor(const Theme &theme) const;
/** Returns the foreground color for selected text of the combination of
* this format and the given theme.
*/
QColor selectedTextColor(const Theme &theme) const;
/** Returns @c true if the combination of this format and the theme @p theme
* change the background color compared to the default format.
*/
bool hasBackgroundColor(const Theme &theme) const;
/** Returns the background color of the combination of this format and the
* given theme.
*/
QColor backgroundColor(const Theme &theme) const;
/** Returns the background color of selected text of the combination of
* this format and the given theme.
*/
QColor selectedBackgroundColor(const Theme &theme) const;
/** Returns @c true if the combination of this format and the given theme
* results in bold text formatting.
*/
bool isBold(const Theme &theme) const;
/** Returns @c true if the combination of this format and the given theme
* results in italic text formatting.
*/
bool isItalic(const Theme &theme) const;
/** Returns @c true if the combination of this format and the given theme
* results in underlined text.
*/
bool isUnderline(const Theme &theme) const;
/** Returns @c true if the combination of this format and the given theme
* results in struck through text.
*/
bool isStrikeThrough(const Theme &theme) const;
/**
* Returns whether characters with this format should be spell checked.
*/
bool spellCheck() const;
private:
friend class FormatPrivate;
QExplicitlySharedDataPointer<FormatPrivate> d;
};
}
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Format, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // KSYNTAXHIGHLIGHTING_FORMAT_H

View File

@@ -0,0 +1,55 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_FORMAT_P_H
#define KSYNTAXHIGHLIGHTING_FORMAT_P_H
#include "definitionref_p.h"
#include "textstyledata_p.h"
#include "theme.h"
#include <QSharedData>
#include <QString>
namespace KSyntaxHighlighting {
class FormatPrivate : public QSharedData
{
public:
FormatPrivate() = default;
static FormatPrivate* detachAndGet(Format &format);
TextStyleData styleOverride(const Theme &theme) const;
void load(QXmlStreamReader &reader);
DefinitionRef definition;
QString name;
TextStyleData style;
Theme::TextStyle defaultStyle = Theme::Normal;
quint16 id = 0;
bool spellCheck = true;
};
}
#endif

View File

@@ -0,0 +1,161 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "htmlhighlighter.h"
#include "definition.h"
#include "format.h"
#include "state.h"
#include "theme.h"
#include "ksyntaxhighlighting_logging.h"
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QVarLengthArray>
using namespace KSyntaxHighlighting;
class KSyntaxHighlighting::HtmlHighlighterPrivate
{
public:
std::unique_ptr<QTextStream> out;
std::unique_ptr<QFile> file;
QString currentLine;
};
HtmlHighlighter::HtmlHighlighter()
: d(new HtmlHighlighterPrivate())
{
}
HtmlHighlighter::~HtmlHighlighter()
{
}
void HtmlHighlighter::setOutputFile(const QString& fileName)
{
d->file.reset(new QFile(fileName));
if (!d->file->open(QFile::WriteOnly | QFile::Truncate)) {
qCWarning(Log) << "Failed to open output file" << fileName << ":" << d->file->errorString();
return;
}
d->out.reset(new QTextStream(d->file.get()));
d->out->setCodec("UTF-8");
}
void HtmlHighlighter::setOutputFile(FILE *fileHandle)
{
d->out.reset(new QTextStream(fileHandle, QIODevice::WriteOnly));
d->out->setCodec("UTF-8");
}
void HtmlHighlighter::highlightFile(const QString& fileName, const QString& title)
{
QFileInfo fi(fileName);
QFile f(fileName);
if (!f.open(QFile::ReadOnly)) {
qCWarning(Log) << "Failed to open input file" << fileName << ":" << f.errorString();
return;
}
if (title.isEmpty())
highlightData(&f, fi.fileName());
else
highlightData(&f, title);
}
void HtmlHighlighter::highlightData(QIODevice *dev, const QString& title)
{
if (!d->out) {
qCWarning(Log) << "No output stream defined!";
return;
}
QString htmlTitle;
if (title.isEmpty())
htmlTitle = QStringLiteral("Kate Syntax Highlighter");
else
htmlTitle = title.toHtmlEscaped();
State state;
*d->out << "<!DOCTYPE html>\n";
*d->out << "<html><head>\n";
*d->out << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n";
*d->out << "<title>" << htmlTitle << "</title>\n";
*d->out << "<meta name=\"generator\" content=\"KF5::SyntaxHighlighting (" << definition().name() << ")\"/>\n";
*d->out << "</head><body";
if (theme().textColor(Theme::Normal))
*d->out << " style=\"color:" << QColor(theme().textColor(Theme::Normal)).name() << "\"";
*d->out << "><pre>\n";
QTextStream in(dev);
in.setCodec("UTF-8");
while (!in.atEnd()) {
d->currentLine = in.readLine();
state = highlightLine(d->currentLine, state);
*d->out << "\n";
}
*d->out << "</pre></body></html>\n";
d->out->flush();
d->out.reset();
d->file.reset();
}
void HtmlHighlighter::applyFormat(int offset, int length, const Format& format)
{
if (length == 0)
return;
// collect potential output, cheaper than thinking about "is there any?"
QVarLengthArray<QString, 16> formatOutput;
if (format.hasTextColor(theme()))
formatOutput << QStringLiteral("color:") << format.textColor(theme()).name() << QStringLiteral(";");
if (format.hasBackgroundColor(theme()))
formatOutput << QStringLiteral("background-color:") << format.backgroundColor(theme()).name() << QStringLiteral(";");
if (format.isBold(theme()))
formatOutput << QStringLiteral("font-weight:bold;");
if (format.isItalic(theme()))
formatOutput << QStringLiteral("font-style:italic;");
if (format.isUnderline(theme()))
formatOutput << QStringLiteral("text-decoration:underline;");
if (format.isStrikeThrough(theme()))
formatOutput << QStringLiteral("text-decoration:line-through;");
if (!formatOutput.isEmpty()) {
*d->out << "<span style=\"";
for (const auto &out : qAsConst(formatOutput)) {
*d->out << out;
}
*d->out << "\">";
}
*d->out << d->currentLine.mid(offset, length).toHtmlEscaped();
if (!formatOutput.isEmpty()) {
*d->out << "</span>";
}
}

View File

@@ -0,0 +1,64 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H
#define KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H
#include "ksyntaxhighlighting_export.h"
#include "abstracthighlighter.h"
#include <QString>
#include <QIODevice>
#include <memory>
QT_BEGIN_NAMESPACE
class QFile;
class QTextStream;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class HtmlHighlighterPrivate;
class KSYNTAXHIGHLIGHTING_EXPORT HtmlHighlighter : public AbstractHighlighter
{
public:
HtmlHighlighter();
~HtmlHighlighter() override;
void highlightFile(const QString &fileName, const QString &title = QString());
void highlightData(QIODevice *device, const QString &title = QString());
void setOutputFile(const QString &fileName);
void setOutputFile(FILE *fileHandle);
protected:
void applyFormat(int offset, int length, const Format &format) override;
private:
std::unique_ptr<HtmlHighlighterPrivate> d;
};
}
#endif // KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H

View File

@@ -0,0 +1,104 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "keywordlist_p.h"
#include <QDebug>
#include <QXmlStreamReader>
#include <algorithm>
using namespace KSyntaxHighlighting;
bool KeywordList::contains(const QStringRef &str, Qt::CaseSensitivity caseSensitive) const
{
/**
* get right vector to search in
*/
const auto &vectorToSearch = (caseSensitive == Qt::CaseSensitive) ? m_keywordsSortedCaseSensitive : m_keywordsSortedCaseInsensitive;
/**
* search with right predicate
*/
return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), str, [caseSensitive] (const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
}
void KeywordList::load(QXmlStreamReader& reader)
{
Q_ASSERT(reader.name() == QLatin1String("list"));
Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
m_name = reader.attributes().value(QStringLiteral("name")).toString();
while (!reader.atEnd()) {
switch (reader.tokenType()) {
case QXmlStreamReader::StartElement:
if (reader.name() == QLatin1String("item")) {
m_keywords.append(reader.readElementText().trimmed());
reader.readNextStartElement();
break;
}
reader.readNext();
break;
case QXmlStreamReader::EndElement:
reader.readNext();
return;
default:
reader.readNext();
break;
}
}
}
void KeywordList::setCaseSensitivity(Qt::CaseSensitivity caseSensitive)
{
/**
* remember default case-sensitivity and init lookup for it
*/
m_caseSensitive = caseSensitive;
initLookupForCaseSensitivity(m_caseSensitive);
}
void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive)
{
/**
* get right vector to sort, if non-empty, we are done
*/
auto &vectorToSort = (caseSensitive == Qt::CaseSensitive) ? m_keywordsSortedCaseSensitive : m_keywordsSortedCaseInsensitive;
if (!vectorToSort.empty()) {
return;
}
/**
* fill vector with refs to keywords
*/
vectorToSort.reserve(m_keywords.size());
for (const auto &keyword : qAsConst(m_keywords)) {
vectorToSort.push_back(&keyword);
}
/**
* sort with right predicate
*/
std::sort(vectorToSort.begin(), vectorToSort.end(), [caseSensitive] (const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
}

View File

@@ -0,0 +1,101 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_KEYWORDLIST_P_H
#define KSYNTAXHIGHLIGHTING_KEYWORDLIST_P_H
#include <QSet>
#include <QString>
#include <QVector>
#include <vector>
QT_BEGIN_NAMESPACE
class QXmlStreamReader;
QT_END_NAMESPACE
namespace KSyntaxHighlighting {
class KeywordList
{
public:
KeywordList() = default;
~KeywordList() = default;
bool isEmpty() const
{
return m_keywords.isEmpty();
}
const QString &name() const
{
return m_name;
}
const QStringList &keywords() const
{
return m_keywords;
}
/** Checks if @p str is a keyword in this list. */
bool contains(const QStringRef &str) const
{
return contains(str, m_caseSensitive);
}
/** Checks if @p str is a keyword in this list, overriding the global case-sensitivity setting. */
bool contains(const QStringRef &str, Qt::CaseSensitivity caseSensitive) const;
void load(QXmlStreamReader &reader);
void setCaseSensitivity(Qt::CaseSensitivity caseSensitive);
void initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive);
private:
/**
* name of keyword list as in XML
*/
QString m_name;
/**
* raw list of keywords, as seen in XML (but trimmed)
*/
QStringList m_keywords;
/**
* default case-sensitivity setting
*/
Qt::CaseSensitivity m_caseSensitive = Qt::CaseSensitive;
/**
* case-sensitive sorted string references to m_keywords for lookup
*/
std::vector<QStringRef> m_keywordsSortedCaseSensitive;
/**
* case-insensitive sorted string references to m_keywords for lookup
*/
std::vector<QStringRef> m_keywordsSortedCaseInsensitive;
};
}
#endif // KSYNTAXHIGHLIGHTING_KEYWORDLIST_P_H

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,16 +25,10 @@
#pragma once
#include <QString>
#include <QtGlobal>
// Replaces the "real" tabsettings.h file.
namespace TextEditor {
class TabSettings
{
public:
int indentationColumn(const QString &) const { return 0; }
};
}
#if defined(KSYNTAXHIGHLIGHTING_LIBRARY)
# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT
#else
# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_IMPORT
#endif

View File

@@ -0,0 +1,113 @@
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KSYNTAXHIGHLIGHTING_MATCHRESULT_P_H
#define KSYNTAXHIGHLIGHTING_MATCHRESULT_P_H
#include <QStringList>
namespace KSyntaxHighlighting {
/**
* Storage for match result of a Rule.
* Heavily used internally during highlightLine, therefore completely inline.
*/
class MatchResult
{
public:
/**
* Match at given offset found.
* @param offset offset of match
*/
MatchResult(const int offset)
: m_offset(offset)
{
}
/**
* Match at given offset found with additional skip offset.
*/
explicit MatchResult(const int offset, const int skipOffset)
: m_offset(offset)
, m_skipOffset(skipOffset)
{
}
/**
* Match at given offset found with additional captures.
* @param offset offset of match
* @param captures captures of the match
*/
explicit MatchResult(const int offset, const QStringList &captures)
: m_offset(offset)
, m_captures(captures)
{
}
/**
* Offset of the match
* @return offset of the match
*/
int offset() const
{
return m_offset;
}
/**
* Skip offset of the match
* @return skip offset of the match, no match possible until this offset is reached
*/
int skipOffset() const
{
return m_skipOffset;
}
/**
* Captures of the match.
* @return captured text of this match
*/
const QStringList &captures() const
{
return m_captures;
}
private:
/**
* match offset, filled in all constructors
*/
int m_offset;
/**
* skip offset, optional
*/
int m_skipOffset = 0;
/**
* captures, optional
*/
QStringList m_captures;
};
}
#endif // KSYNTAXHIGHLIGHTING_MATCHRESULT_P_H

Some files were not shown because too many files have changed in this diff Show More