mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
SyntaxTokenizer: improve the stack-based pattern matching to support include / repositories.
Added some *very basic* support for some *very basic* TextMate grammars, `$language.tmLanguage.json` files are now parsed and supported internally. Full support is not currently possible, and might never be. This is to facilitate converting grammars to ecode format. Updated python linter and formatter to the latest ruff version.
This commit is contained in:
@@ -169,7 +169,7 @@
|
||||
"eepp-linux": {
|
||||
"build": [
|
||||
{
|
||||
"args": "--disable-static-build --with-text-shaper gmake",
|
||||
"args": "--disable-static-build --with-text-shaper --with-debug-symbols gmake",
|
||||
"command": "premake4",
|
||||
"working_dir": "${project_root}"
|
||||
},
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
{
|
||||
"language": "python",
|
||||
"file_patterns": ["%.py$", "%.pyw$"],
|
||||
"command": "black $FILENAME",
|
||||
"command": "ruff format $FILENAME",
|
||||
"type": "inplace",
|
||||
"url": "https://black.readthedocs.io/en/stable/"
|
||||
},
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"language": "python",
|
||||
"file_patterns": ["%.py$"],
|
||||
"warning_pattern": "[^:]:(%d+):(%d+):%s([^\n]+)",
|
||||
"command": "ruff $FILENAME",
|
||||
"command": "ruff check $FILENAME",
|
||||
"url": "https://ruff.rs"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -32,17 +32,18 @@ enum class SyntaxPatternMatchType { LuaPattern, RegEx, Parser };
|
||||
|
||||
class SyntaxDefinition;
|
||||
|
||||
template <typename Key, typename Value> using SyntaxDefMap = UnorderedMap<Key, Value>;
|
||||
|
||||
struct EE_API SyntaxPattern {
|
||||
enum Flags {
|
||||
IsPure = 1 << 0,
|
||||
IsInclude = 1 << 1,
|
||||
IsRepositoryInclude = 1 << 2,
|
||||
IsRootSelfInclude = 1 << 3,
|
||||
IsInherited = 1 << 4,
|
||||
IsRangedMatch = 1 << 5,
|
||||
};
|
||||
|
||||
static UnorderedMap<SyntaxStyleType, std::string> SyntaxStyleTypeCache;
|
||||
static SyntaxDefMap<SyntaxStyleType, std::string> SyntaxStyleTypeCache;
|
||||
|
||||
using DynamicSyntax =
|
||||
std::function<std::string( const SyntaxPattern&, const std::string_view& )>;
|
||||
@@ -93,8 +94,6 @@ struct EE_API SyntaxPattern {
|
||||
|
||||
inline bool isRootSelfInclude() const { return flags & Flags::IsRootSelfInclude; }
|
||||
|
||||
inline bool isInherited() const { return flags & Flags::IsInherited; }
|
||||
|
||||
inline bool isRangedMatch() const { return flags & Flags::IsRangedMatch; }
|
||||
|
||||
std::string_view getRepositoryName() const {
|
||||
@@ -126,7 +125,7 @@ class EE_API SyntaxDefinition {
|
||||
|
||||
SyntaxDefinition( const std::string& languageName, std::vector<std::string>&& files,
|
||||
std::vector<SyntaxPattern>&& patterns,
|
||||
UnorderedMap<std::string, std::string>&& symbols = {},
|
||||
SyntaxDefMap<std::string, std::string>&& symbols = {},
|
||||
const std::string& comment = "", std::vector<std::string>&& headers = {},
|
||||
const std::string& lspName = "" );
|
||||
|
||||
@@ -144,7 +143,7 @@ class EE_API SyntaxDefinition {
|
||||
|
||||
const std::string& getComment() const;
|
||||
|
||||
const UnorderedMap<std::string, SyntaxStyleType>& getSymbols() const;
|
||||
const SyntaxDefMap<std::string, SyntaxStyleType>& getSymbols() const;
|
||||
|
||||
SyntaxStyleType getSymbol( const std::string& symbol ) const;
|
||||
|
||||
@@ -164,8 +163,8 @@ class EE_API SyntaxDefinition {
|
||||
SyntaxDefinition& addSymbols( const std::vector<std::string>& symbolNames,
|
||||
const std::string& typeName );
|
||||
|
||||
SyntaxDefinition& setSymbols( const UnorderedMap<std::string, SyntaxStyleType>& symbols,
|
||||
const UnorderedMap<std::string, std::string>& symbolNames );
|
||||
SyntaxDefinition& setSymbols( const SyntaxDefMap<std::string, SyntaxStyleType>& symbols,
|
||||
const SyntaxDefMap<std::string, std::string>& symbolNames );
|
||||
|
||||
/** Sets the comment string used for auto-comment functionality. */
|
||||
SyntaxDefinition& setComment( const std::string& comment );
|
||||
@@ -200,7 +199,7 @@ class EE_API SyntaxDefinition {
|
||||
|
||||
SyntaxDefinition& setExtensionPriority( bool hasExtensionPriority );
|
||||
|
||||
UnorderedMap<std::string, std::string> getSymbolNames() const;
|
||||
SyntaxDefMap<std::string, std::string> getSymbolNames() const;
|
||||
|
||||
const Uint16& getLanguageIndex() const { return mLanguageIndex; }
|
||||
|
||||
@@ -216,7 +215,7 @@ class EE_API SyntaxDefinition {
|
||||
|
||||
SyntaxDefinition& setFoldBraces( const std::vector<std::pair<Int64, Int64>>& foldBraces );
|
||||
|
||||
SyntaxDefinition& setRepository( const std::string& name,
|
||||
SyntaxDefinition& addRepository( const std::string& name,
|
||||
std::vector<SyntaxPattern>&& patterns );
|
||||
|
||||
const std::vector<SyntaxPattern>& getRepository( String::HashType hash ) const;
|
||||
@@ -229,6 +228,12 @@ class EE_API SyntaxDefinition {
|
||||
|
||||
String::HashType getRepositoryHash( Uint32 index ) const;
|
||||
|
||||
std::string getRepositoryName( String::HashType hash ) const;
|
||||
|
||||
const SyntaxDefMap<String::HashType, std::vector<SyntaxPattern>>& getRepositories() const;
|
||||
|
||||
const SyntaxDefMap<String::HashType, std::string>& getRepositoriesNames() const;
|
||||
|
||||
SyntaxDefinition& addAlternativeName( const std::string& name );
|
||||
|
||||
const std::vector<std::string>& getAlternativeNames() const;
|
||||
@@ -242,8 +247,8 @@ class EE_API SyntaxDefinition {
|
||||
String::HashType mLanguageId;
|
||||
std::vector<std::string> mFiles;
|
||||
std::vector<SyntaxPattern> mPatterns;
|
||||
UnorderedMap<std::string, SyntaxStyleType> mSymbols;
|
||||
UnorderedMap<std::string, std::string> mSymbolNames;
|
||||
SyntaxDefMap<std::string, SyntaxStyleType> mSymbols;
|
||||
SyntaxDefMap<std::string, std::string> mSymbolNames;
|
||||
std::string mComment;
|
||||
std::vector<std::string> mHeaders;
|
||||
std::string mLSPName;
|
||||
@@ -254,9 +259,10 @@ class EE_API SyntaxDefinition {
|
||||
bool mVisible{ true };
|
||||
bool mHasExtensionPriority{ false };
|
||||
bool mCaseInsensitive{ false };
|
||||
UnorderedMap<String::HashType, std::vector<SyntaxPattern>> mRepository;
|
||||
UnorderedMap<String::HashType, Uint32> mRepositoryIndex;
|
||||
UnorderedMap<Uint32, String::HashType> mRepositoryIndexInvert;
|
||||
SyntaxDefMap<String::HashType, std::vector<SyntaxPattern>> mRepository;
|
||||
SyntaxDefMap<String::HashType, Uint32> mRepositoryIndex;
|
||||
SyntaxDefMap<String::HashType, std::string> mRepositoryNames;
|
||||
SyntaxDefMap<Uint32, String::HashType> mRepositoryIndexInvert;
|
||||
std::vector<std::string> mLanguageAlternativeNames;
|
||||
Uint32 mRepositoryIndexCounter{ 0 };
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
-std=c17
|
||||
-std=c20
|
||||
|
||||
@@ -1 +1 @@
|
||||
-std=c++17
|
||||
-std=c++20
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <eepp/core/memorymanager.hpp>
|
||||
#include <eepp/core/string.hpp>
|
||||
#include <eepp/system/log.hpp>
|
||||
#include <eepp/system/parsermatcher.hpp>
|
||||
#include <eepp/ui/doc/syntaxdefinition.hpp>
|
||||
#include <eepp/ui/doc/syntaxdefinitionmanager.hpp>
|
||||
@@ -8,7 +9,7 @@ using namespace std::literals;
|
||||
|
||||
namespace EE { namespace UI { namespace Doc {
|
||||
|
||||
UnorderedMap<SyntaxStyleType, std::string> SyntaxPattern::SyntaxStyleTypeCache = {};
|
||||
SyntaxDefMap<SyntaxStyleType, std::string> SyntaxPattern::SyntaxStyleTypeCache = {};
|
||||
|
||||
template <typename SyntaxStyleType> void updateCache( const SyntaxPattern& ptrn ) {
|
||||
if constexpr ( std::is_same_v<SyntaxStyleType, std::string> ) {
|
||||
@@ -38,27 +39,32 @@ static void updatePatternRefs( const SyntaxDefinition& def, SyntaxPattern& ptrn
|
||||
ptrn.syntax = def.getLanguageName();
|
||||
}
|
||||
|
||||
static void updatePatternState( SyntaxDefinition& def, std::vector<SyntaxPattern>& ptrns ) {
|
||||
for ( auto& ptrn : ptrns ) {
|
||||
if ( ptrn.checkIsRangedMatch() )
|
||||
ptrn.flags |= SyntaxPattern::IsRangedMatch;
|
||||
static void updatePatternState( SyntaxDefinition& def, SyntaxPattern& ptrn ) {
|
||||
if ( ptrn.checkIsRangedMatch() )
|
||||
ptrn.flags |= SyntaxPattern::IsRangedMatch;
|
||||
|
||||
if ( ptrn.checkIsIncludePattern() ) {
|
||||
ptrn.flags |= SyntaxPattern::IsInclude;
|
||||
if ( ptrn.checkIsIncludePattern() ) {
|
||||
ptrn.flags |= SyntaxPattern::IsInclude;
|
||||
|
||||
if ( ptrn.checkIsRepositoryInclude() ) {
|
||||
ptrn.flags |= SyntaxPattern::IsRepositoryInclude;
|
||||
ptrn.repositoryIdx = def.getRepositoryIndex( ptrn.getRepositoryName() );
|
||||
}
|
||||
|
||||
if ( ptrn.checkIsRootSelfInclude() )
|
||||
ptrn.flags |= SyntaxPattern::IsRootSelfInclude;
|
||||
if ( ptrn.checkIsRepositoryInclude() ) {
|
||||
ptrn.flags |= SyntaxPattern::IsRepositoryInclude;
|
||||
ptrn.repositoryIdx = def.getRepositoryIndex( ptrn.getRepositoryName() );
|
||||
} else if ( ptrn.checkIsRootSelfInclude() ) {
|
||||
ptrn.flags |= SyntaxPattern::IsRootSelfInclude;
|
||||
} else {
|
||||
ptrn.flags |= SyntaxPattern::IsPure;
|
||||
Log::warning( "updatePatternState unknown include directive: %s", ptrn.patterns[1] );
|
||||
ptrn.flags &= ~SyntaxPattern::IsInclude;
|
||||
}
|
||||
|
||||
updatePatternRefs( def, ptrn );
|
||||
} else {
|
||||
ptrn.flags |= SyntaxPattern::IsPure;
|
||||
}
|
||||
|
||||
updatePatternRefs( def, ptrn );
|
||||
}
|
||||
|
||||
static void updatePatternsState( SyntaxDefinition& def, std::vector<SyntaxPattern>& ptrns ) {
|
||||
for ( auto& ptrn : ptrns )
|
||||
updatePatternState( def, ptrn );
|
||||
}
|
||||
|
||||
static void updateRepoIndexState( SyntaxDefinition& def, std::vector<SyntaxPattern>& ptrns ) {
|
||||
@@ -72,7 +78,7 @@ SyntaxDefinition::SyntaxDefinition() {}
|
||||
SyntaxDefinition::SyntaxDefinition( const std::string& languageName,
|
||||
std::vector<std::string>&& files,
|
||||
std::vector<SyntaxPattern>&& patterns,
|
||||
UnorderedMap<std::string, std::string>&& symbols,
|
||||
SyntaxDefMap<std::string, std::string>&& symbols,
|
||||
const std::string& comment, std::vector<std::string>&& headers,
|
||||
const std::string& lspName ) :
|
||||
mLanguageName( languageName ),
|
||||
@@ -90,7 +96,7 @@ SyntaxDefinition::SyntaxDefinition( const std::string& languageName,
|
||||
return pattern.matchType == SyntaxPatternMatchType::Parser;
|
||||
} ) )
|
||||
ParserMatcherManager::instance()->registerBaseParsers();
|
||||
updatePatternState( *this, mPatterns );
|
||||
updatePatternsState( *this, mPatterns );
|
||||
mPatterns.emplace_back( SyntaxPattern{ { "%s+" }, "normal" } );
|
||||
mPatterns.emplace_back( SyntaxPattern{ { "%w+%f[%s]" }, "normal" } );
|
||||
}
|
||||
@@ -137,7 +143,7 @@ SyntaxDefinition& SyntaxDefinition::setExtensionPriority( bool hasExtensionPrior
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnorderedMap<std::string, std::string> SyntaxDefinition::getSymbolNames() const {
|
||||
SyntaxDefMap<std::string, std::string> SyntaxDefinition::getSymbolNames() const {
|
||||
return mSymbolNames;
|
||||
}
|
||||
|
||||
@@ -177,7 +183,7 @@ const std::string& SyntaxDefinition::getComment() const {
|
||||
return mComment;
|
||||
}
|
||||
|
||||
const UnorderedMap<std::string, SyntaxStyleType>& SyntaxDefinition::getSymbols() const {
|
||||
const SyntaxDefMap<std::string, SyntaxStyleType>& SyntaxDefinition::getSymbols() const {
|
||||
return mSymbols;
|
||||
}
|
||||
|
||||
@@ -195,6 +201,7 @@ SyntaxDefinition& SyntaxDefinition::addFileType( const std::string& fileType ) {
|
||||
|
||||
SyntaxDefinition& SyntaxDefinition::addPattern( const SyntaxPattern& pattern ) {
|
||||
mPatterns.push_back( pattern );
|
||||
updatePatternState( *this, mPatterns[mPatterns.size() - 1] );
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -229,8 +236,8 @@ SyntaxDefinition& SyntaxDefinition::addSymbols( const std::vector<std::string>&
|
||||
}
|
||||
|
||||
SyntaxDefinition&
|
||||
SyntaxDefinition::setSymbols( const UnorderedMap<std::string, SyntaxStyleType>& symbols,
|
||||
const UnorderedMap<std::string, std::string>& symbolNames ) {
|
||||
SyntaxDefinition::setSymbols( const SyntaxDefMap<std::string, SyntaxStyleType>& symbols,
|
||||
const SyntaxDefMap<std::string, std::string>& symbolNames ) {
|
||||
mSymbols = symbols;
|
||||
mSymbolNames = symbolNames;
|
||||
return *this;
|
||||
@@ -383,14 +390,15 @@ SyntaxPattern::SyntaxPattern( std::vector<std::string>&& _patterns,
|
||||
updateCache<SyntaxStyleType>( *this );
|
||||
}
|
||||
|
||||
SyntaxDefinition& SyntaxDefinition::setRepository( const std::string& name,
|
||||
SyntaxDefinition& SyntaxDefinition::addRepository( const std::string& name,
|
||||
std::vector<SyntaxPattern>&& patterns ) {
|
||||
updatePatternState( *this, patterns );
|
||||
updateRepoIndexState( *this, mPatterns );
|
||||
auto hash = String::hash( name );
|
||||
mRepository[hash] = std::move( patterns );
|
||||
mRepositoryIndex[hash] = ++mRepositoryIndexCounter;
|
||||
mRepositoryNames[hash] = name;
|
||||
mRepositoryIndexInvert[mRepositoryIndexCounter] = hash;
|
||||
updatePatternsState( *this, patterns );
|
||||
mRepository[hash] = std::move( patterns );
|
||||
updateRepoIndexState( *this, mPatterns );
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -444,4 +452,18 @@ const SyntaxPattern* SyntaxDefinition::getPatternFromState( const SyntaxStateTyp
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SyntaxDefMap<String::HashType, std::vector<SyntaxPattern>>&
|
||||
SyntaxDefinition::getRepositories() const {
|
||||
return mRepository;
|
||||
}
|
||||
|
||||
const SyntaxDefMap<String::HashType, std::string>& SyntaxDefinition::getRepositoriesNames() const {
|
||||
return mRepositoryNames;
|
||||
}
|
||||
|
||||
std::string SyntaxDefinition::getRepositoryName( String::HashType hash ) const {
|
||||
auto it = mRepositoryNames.find( hash );
|
||||
return it != mRepositoryNames.end() ? it->second : "";
|
||||
}
|
||||
|
||||
}}} // namespace EE::UI::Doc
|
||||
|
||||
@@ -25,6 +25,97 @@ using json = nlohmann::json;
|
||||
|
||||
namespace EE { namespace UI { namespace Doc {
|
||||
|
||||
class TextMateScopeMapper {
|
||||
private:
|
||||
// Define the mapping from TM scope prefixes to ecode types.
|
||||
// Use string_view for efficiency.
|
||||
// **IMPORTANT**: This vector MUST be sorted by the length of the TM prefix
|
||||
// in DESCENDING order to ensure more specific matches are
|
||||
// checked first (e.g., "keyword.control" before "keyword").
|
||||
// We initialize it sorted here.
|
||||
inline static const std::vector<std::pair<std::string_view, std::string_view>> scope_map_ = {
|
||||
// -- Most Specific --
|
||||
{ "markup.underline.link", "link" }, // Specific markup
|
||||
{ "constant.character.escape", "string" }, // Escapes within strings
|
||||
{ "variable.parameter", "keyword3" }, // Function parameters
|
||||
{ "variable.language", "literal" }, // Language constants like 'this', 'self', 'null'?
|
||||
{ "storage.type", "keyword2" }, // Class, struct, int, bool etc. (declaration)
|
||||
{ "entity.name.function", "function" }, // Function definition name
|
||||
{ "entity.name.type", "keyword2" }, // Type name (class, struct, etc.) in definition
|
||||
{ "entity.name.class", "keyword2" }, // Class name in definition
|
||||
{ "entity.name.struct", "keyword2" }, // Struct name in definition
|
||||
{ "entity.name.interface", "keyword2" }, // Interface name in definition
|
||||
{ "entity.name.tag", "keyword2" }, // HTML/XML tag name
|
||||
{ "keyword.control", "keyword" }, // if, else, for, while, return etc.
|
||||
{ "keyword.operator", "operator" }, // +, -, =, and, or, etc.
|
||||
{ "punctuation.definition.tag", "operator" }, // <, >, </ in HTML/XML
|
||||
{ "support.function", "function" }, // Built-in functions (print, len)
|
||||
{ "support.type", "keyword2" }, // Built-in types (string, list)
|
||||
{ "support.class", "keyword2" }, // Built-in classes
|
||||
{ "storage.modifier", "keyword" }, // public, private, static, const etc.
|
||||
{ "constant.numeric", "number" }, // Numbers
|
||||
{ "constant.language", "literal" }, // true, false, null etc.
|
||||
{ "comment.unused", "normal" }, // unused comments pattern
|
||||
|
||||
// -- General Categories --
|
||||
{ "comment", "comment" }, // Comments
|
||||
{ "string", "string" }, // Strings
|
||||
{ "keyword", "keyword" }, // Any other keyword
|
||||
{ "storage", "keyword" }, // Fallback for storage (like storage.type)
|
||||
{ "operator", "operator" }, // Fallback for operators (less common)
|
||||
{ "punctuation", "operator" }, // General punctuation -> operator is often suitable
|
||||
{ "constant", "literal" }, // Any other constant (fallback)
|
||||
{ "entity", "normal" }, // General entities (fallback, often unstyled)
|
||||
{ "variable", "normal" }, // General variables (fallback, often unstyled)
|
||||
{ "support", "normal" }, // General support scopes (fallback)
|
||||
{ "markup", "normal" } // General markup (fallback)
|
||||
// "meta" scopes are intentionally left out. They define structure,
|
||||
// not usually the token type itself. If no inner scope matches,
|
||||
// it will eventually fall back to "normal".
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Maps a TextMate scope string to an ecode syntax highlighting type.
|
||||
*
|
||||
* This function takes a full TextMate scope string (e.g., "keyword.control.if.python")
|
||||
* and finds the most specific matching prefix in its internal mapping table
|
||||
* to determine the appropriate ecode type (e.g., "keyword").
|
||||
*
|
||||
* The matching prioritizes longer prefixes (more specific rules) over shorter ones.
|
||||
* For example, "keyword.control.if" will match "keyword.control" -> "keyword"
|
||||
* before it could match "keyword" -> "keyword".
|
||||
*
|
||||
* Scopes starting with "meta." generally describe code structure and do not
|
||||
* directly map to a type themselves, unless a more specific inner rule matches.
|
||||
* If no specific rule matches, the default type "normal" is returned.
|
||||
*
|
||||
* @param scopeName The TextMate scope string to map.
|
||||
* @return The corresponding ecode type string (e.g., "keyword", "string", "comment", "normal").
|
||||
*/
|
||||
static std::string scopeToType( const std::string_view scopeName ) {
|
||||
if ( scopeName.empty() ) {
|
||||
return "normal"; // Default for empty scope
|
||||
}
|
||||
|
||||
// Iterate through the pre-sorted map (longest prefix first)
|
||||
for ( const auto& mapping : scope_map_ ) {
|
||||
const std::string_view tmPrefix = mapping.first;
|
||||
// Check if scopeName starts with tmPrefix
|
||||
if ( scopeName.starts_with( tmPrefix ) ) {
|
||||
// Make sure it's either the full scope or followed by a '.'
|
||||
// (prevents "stringBuffer" matching "string")
|
||||
if ( scopeName.size() == tmPrefix.size() || scopeName[tmPrefix.size()] == '.' ) {
|
||||
return std::string( mapping.second ); // Return the corresponding ecode type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no prefix matched, return the default type
|
||||
return "normal";
|
||||
}
|
||||
};
|
||||
|
||||
SINGLETON_DECLARE_IMPLEMENTATION( SyntaxDefinitionManager )
|
||||
|
||||
SyntaxDefinitionManager*
|
||||
@@ -70,6 +161,46 @@ const std::vector<SyntaxDefinition>& SyntaxDefinitionManager::getDefinitions() c
|
||||
}
|
||||
|
||||
static json toJson( const SyntaxDefinition& def ) {
|
||||
const auto serializePattern =
|
||||
[&def]( const SyntaxPattern& ptrn ) -> std::optional<nlohmann::json> {
|
||||
json pattern;
|
||||
auto ptrnType =
|
||||
ptrn.matchType == SyntaxPatternMatchType::RegEx
|
||||
? "regex"
|
||||
: ( ptrn.matchType == SyntaxPatternMatchType::Parser ? "parser" : "pattern" );
|
||||
|
||||
// Do not export injected patterns
|
||||
if ( ptrn.matchType == SyntaxPatternMatchType::LuaPattern && ptrn.patterns.size() == 1 &&
|
||||
( ptrn.patterns[0] == "%s+" || ptrn.patterns[0] == "%w+%f[%s]" ) )
|
||||
return {};
|
||||
|
||||
bool hasInclude = false;
|
||||
if ( ptrn.patterns.size() == 2 && ptrn.patterns[0] == "include" ) {
|
||||
hasInclude = true;
|
||||
pattern["include"] = ptrn.patterns[1];
|
||||
} else if ( ptrn.patterns.size() == 1 ) {
|
||||
pattern[ptrnType] = ptrn.patterns[0];
|
||||
} else if ( ptrn.patterns.size() ) {
|
||||
pattern[ptrnType] = ptrn.patterns;
|
||||
}
|
||||
|
||||
if ( !hasInclude ) {
|
||||
if ( ptrn.typesNames.size() == 1 ) {
|
||||
pattern["type"] = ptrn.typesNames[0];
|
||||
} else if ( ptrn.typesNames.size() ) {
|
||||
pattern["type"] = ptrn.typesNames;
|
||||
}
|
||||
if ( ptrn.endTypesNames.size() == 1 ) {
|
||||
pattern["end_type"] = ptrn.endTypesNames[0];
|
||||
} else if ( ptrn.endTypesNames.size() ) {
|
||||
pattern["end_type"] = ptrn.endTypesNames;
|
||||
}
|
||||
if ( !ptrn.syntax.empty() )
|
||||
pattern["syntax"] = ptrn.syntax == def.getLanguageName() ? "$self" : ptrn.syntax;
|
||||
}
|
||||
return pattern;
|
||||
};
|
||||
|
||||
json j;
|
||||
j["name"] = def.getLanguageName();
|
||||
if ( def.getLSPName() != String::toLower( def.getLanguageName() ) )
|
||||
@@ -80,36 +211,9 @@ static json toJson( const SyntaxDefinition& def ) {
|
||||
if ( !def.getPatterns().empty() ) {
|
||||
j["patterns"] = json::array();
|
||||
for ( const auto& ptrn : def.getPatterns() ) {
|
||||
json pattern;
|
||||
auto ptrnType =
|
||||
ptrn.matchType == SyntaxPatternMatchType::RegEx
|
||||
? "regex"
|
||||
: ( ptrn.matchType == SyntaxPatternMatchType::Parser ? "parser" : "pattern" );
|
||||
|
||||
// Do not export injected patterns
|
||||
if ( ptrn.matchType == SyntaxPatternMatchType::LuaPattern &&
|
||||
ptrn.patterns.size() == 1 &&
|
||||
( ptrn.patterns[0] == "%s+" || ptrn.patterns[0] == "%w+%f[%s]" ) )
|
||||
continue;
|
||||
|
||||
if ( ptrn.patterns.size() == 1 ) {
|
||||
pattern[ptrnType] = ptrn.patterns[0];
|
||||
} else {
|
||||
pattern[ptrnType] = ptrn.patterns;
|
||||
}
|
||||
if ( ptrn.typesNames.size() == 1 ) {
|
||||
pattern["type"] = ptrn.typesNames[0];
|
||||
} else {
|
||||
pattern["type"] = ptrn.typesNames;
|
||||
}
|
||||
if ( ptrn.endTypesNames.size() == 1 ) {
|
||||
pattern["end_type"] = ptrn.endTypesNames[0];
|
||||
} else {
|
||||
pattern["end_type"] = ptrn.endTypesNames;
|
||||
}
|
||||
if ( !ptrn.syntax.empty() )
|
||||
pattern["syntax"] = ptrn.syntax;
|
||||
j["patterns"].emplace_back( std::move( pattern ) );
|
||||
auto pattern = serializePattern( ptrn );
|
||||
if ( pattern )
|
||||
j["patterns"].emplace_back( std::move( *pattern ) );
|
||||
}
|
||||
}
|
||||
if ( !def.getSymbols().empty() ) {
|
||||
@@ -141,6 +245,22 @@ static json toJson( const SyntaxDefinition& def ) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( !def.getRepositories().empty() ) {
|
||||
j["repository"] = json::object();
|
||||
auto& repository = j["repository"];
|
||||
|
||||
for ( const auto& [hash, patterns] : def.getRepositories() ) {
|
||||
std::string name = def.getRepositoryName( hash );
|
||||
nlohmann::json repo;
|
||||
for ( const auto& pattern : patterns ) {
|
||||
auto ojptrn = serializePattern( pattern );
|
||||
if ( ojptrn )
|
||||
repo.emplace_back( std::move( *ojptrn ) );
|
||||
}
|
||||
repository.emplace( name, std::move( repo ) );
|
||||
}
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
@@ -423,12 +543,196 @@ SyntaxDefinitionManager::getPtrByLanguageId( const String::HashType& id ) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static SyntaxPattern parsePattern( const nlohmann::json& pattern ) {
|
||||
std::vector<std::string> type;
|
||||
std::vector<std::string> endType;
|
||||
std::vector<std::string> ptrns;
|
||||
auto ctype = SyntaxPatternMatchType::LuaPattern;
|
||||
std::string syntax;
|
||||
|
||||
const auto fillTypes = []( const nlohmann::json& captures, std::vector<std::string>& type ) {
|
||||
Uint64 totalCaptures = 0;
|
||||
for ( const auto& [capNumStr, _] : captures.items() ) {
|
||||
Uint64 num;
|
||||
if ( String::fromString( num, capNumStr ) )
|
||||
totalCaptures = eemax( totalCaptures, num + 1 );
|
||||
}
|
||||
|
||||
for ( Uint64 i = 0; i < totalCaptures; i++ ) {
|
||||
auto capNumStr = String::toString( i );
|
||||
if ( captures.contains( capNumStr ) && captures[capNumStr].contains( "name" ) ) {
|
||||
type.emplace_back(
|
||||
TextMateScopeMapper::scopeToType( captures[capNumStr].value( "name", "" ) ) );
|
||||
} else {
|
||||
type.emplace_back( "normal" );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Assume TextMate pattern
|
||||
if ( pattern.contains( "name" ) || pattern.contains( "begin" ) ) {
|
||||
ctype = SyntaxPatternMatchType::RegEx;
|
||||
|
||||
if ( pattern.contains( "beginCaptures" ) )
|
||||
fillTypes( pattern["beginCaptures"], type );
|
||||
|
||||
if ( pattern.contains( "endCaptures" ) )
|
||||
fillTypes( pattern["endCaptures"], endType );
|
||||
|
||||
if ( type.empty() && pattern.contains( "captures" ) )
|
||||
fillTypes( pattern["captures"], type );
|
||||
|
||||
if ( type.empty() && pattern.contains( "name" ) ) {
|
||||
type.emplace_back( TextMateScopeMapper::scopeToType( pattern.value( "name", "" ) ) );
|
||||
}
|
||||
|
||||
if ( pattern.contains( "match" ) && pattern["match"].is_string() ) {
|
||||
ptrns.emplace_back( pattern.value( "match", "" ) );
|
||||
} else if ( pattern.contains( "include" ) ) {
|
||||
ptrns.emplace_back( "include" );
|
||||
ptrns.emplace_back( pattern.value( "include", "" ) );
|
||||
}
|
||||
|
||||
if ( pattern.contains( "begin" ) )
|
||||
ptrns.emplace_back( pattern.value( "begin", "" ) );
|
||||
|
||||
if ( pattern.contains( "end" ) )
|
||||
ptrns.emplace_back( pattern.value( "end", "" ) );
|
||||
|
||||
// Sub-languages?
|
||||
if ( pattern.contains( "patterns" ) && !pattern["patterns"].empty() ) {
|
||||
const auto& patterns = pattern["patterns"];
|
||||
if ( patterns.size() == 1 && patterns[0].is_object() ) {
|
||||
if ( patterns[0].contains( "include" ) &&
|
||||
patterns[0].value( "include", "" ) == "$self" ) {
|
||||
syntax = "$self";
|
||||
}
|
||||
|
||||
if ( patterns[0].contains( "name" ) && patterns[0].contains( "match" ) &&
|
||||
patterns[0].value( "name", "" ).starts_with( "constant.character.escape" ) ) {
|
||||
ptrns.emplace_back( patterns[0].value( "match", "" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if ( pattern.contains( "syntax" ) && pattern["syntax"].is_string() )
|
||||
syntax = pattern.value( "syntax", "" );
|
||||
|
||||
if ( pattern.contains( "type" ) ) {
|
||||
if ( pattern["type"].is_array() ) {
|
||||
for ( const auto& t : pattern["type"] ) {
|
||||
if ( t.is_string() )
|
||||
type.emplace_back( t.get<std::string>() );
|
||||
}
|
||||
} else if ( pattern["type"].is_string() ) {
|
||||
type.emplace_back( pattern["type"] );
|
||||
}
|
||||
} else {
|
||||
type.emplace_back( "normal" );
|
||||
}
|
||||
|
||||
if ( pattern.contains( "end_type" ) ) {
|
||||
if ( pattern["end_type"].is_array() ) {
|
||||
for ( const auto& t : pattern["end_type"] ) {
|
||||
if ( t.is_string() )
|
||||
endType.emplace_back( t.get<std::string>() );
|
||||
}
|
||||
} else if ( pattern["end_type"].is_string() ) {
|
||||
endType.emplace_back( pattern["end_type"] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( pattern.contains( "include" ) ) {
|
||||
ptrns.emplace_back( "include" );
|
||||
ptrns.emplace_back( pattern.value( "include", "" ) );
|
||||
} else if ( pattern.contains( "pattern" ) ) {
|
||||
if ( pattern["pattern"].is_array() ) {
|
||||
const auto& ptrnIt = pattern["pattern"];
|
||||
for ( const auto& ptrn : ptrnIt )
|
||||
ptrns.emplace_back( ptrn );
|
||||
} else if ( pattern["pattern"].is_string() ) {
|
||||
ptrns.emplace_back( pattern["pattern"] );
|
||||
}
|
||||
} else if ( pattern.contains( "regex" ) ) {
|
||||
ctype = SyntaxPatternMatchType::RegEx;
|
||||
if ( pattern["regex"].is_array() ) {
|
||||
const auto& ptrnIt = pattern["regex"];
|
||||
for ( const auto& ptrn : ptrnIt )
|
||||
ptrns.emplace_back( ptrn );
|
||||
} else if ( pattern["regex"].is_string() ) {
|
||||
ptrns.emplace_back( pattern["regex"] );
|
||||
}
|
||||
} else if ( pattern.contains( "parser" ) ) {
|
||||
ctype = SyntaxPatternMatchType::Parser;
|
||||
if ( pattern["parser"].is_array() ) {
|
||||
const auto& ptrnIt = pattern["parser"];
|
||||
for ( const auto& ptrn : ptrnIt )
|
||||
ptrns.emplace_back( ptrn );
|
||||
} else if ( pattern["parser"].is_string() ) {
|
||||
ptrns.emplace_back( pattern["parser"] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eeASSERT( !ptrns.empty() );
|
||||
|
||||
return SyntaxPattern( std::move( ptrns ), std::move( type ), std::move( endType ), syntax,
|
||||
ctype );
|
||||
}
|
||||
|
||||
static SyntaxDefinition loadTextMateLanguage( const nlohmann::json& json, SyntaxDefinition& def ) {
|
||||
if ( json.contains( "fileTypes" ) && json["fileTypes"].is_array() ) {
|
||||
const auto& files = json["fileTypes"];
|
||||
for ( const auto& file : files )
|
||||
if ( file.is_string() ) {
|
||||
auto ext( file.get<std::string>() );
|
||||
def.addFileType( ( !String::contains( ext, "." ) ? "%." : "" ) + ext + "$" );
|
||||
}
|
||||
} else if ( json.contains( "scopeName" ) && json["scopeName"].is_string() ) {
|
||||
const auto& scopeName = json.value( "scopeName", "" );
|
||||
def.addFileType( "%." + FileSystem::fileExtension( scopeName ) + "$" );
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
static SyntaxDefinition loadLanguage( const nlohmann::json& json ) {
|
||||
SyntaxDefinition def;
|
||||
|
||||
try {
|
||||
def.setLanguageName( json.value( "name", "" ) );
|
||||
|
||||
if ( json.contains( "patterns" ) && json["patterns"].is_array() ) {
|
||||
const auto& patterns = json["patterns"];
|
||||
for ( const auto& pattern : patterns )
|
||||
def.addPattern( parsePattern( pattern ) );
|
||||
}
|
||||
|
||||
if ( json.contains( "repository" ) && json["repository"].is_object() ) {
|
||||
const auto& repository = json["repository"];
|
||||
for ( const auto& [name, repository] : repository.items() ) {
|
||||
std::vector<SyntaxPattern> ptrns;
|
||||
if ( repository.contains( "match" ) || repository.contains( "begin" ) ) {
|
||||
ptrns.emplace_back( parsePattern( repository ) );
|
||||
} else if ( repository.contains( "patterns" ) &&
|
||||
repository["patterns"].is_array() ) {
|
||||
const auto& patterns = repository["patterns"];
|
||||
for ( const auto& pattern : patterns )
|
||||
ptrns.emplace_back( parsePattern( pattern ) );
|
||||
}
|
||||
def.addRepository( name, std::move( ptrns ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( json.contains( "$schema" ) && json["$schema"].is_string() &&
|
||||
String::contains( json.value( "$schema", "" ), "tmlanguage.json" ) ) ||
|
||||
json.contains( "scopeName" ) /* assume tmlanguage */ ) {
|
||||
return loadTextMateLanguage( json, def );
|
||||
}
|
||||
|
||||
if ( json.contains( "lsp_name" ) && json["lsp_name"].is_string() )
|
||||
def.setLSPName( json["lsp_name"].get<std::string>() );
|
||||
|
||||
if ( json.contains( "files" ) ) {
|
||||
if ( json["files"].is_array() ) {
|
||||
const auto& files = json["files"];
|
||||
@@ -439,73 +743,9 @@ static SyntaxDefinition loadLanguage( const nlohmann::json& json ) {
|
||||
def.addFileType( json["files"].get<std::string>() );
|
||||
}
|
||||
}
|
||||
|
||||
def.setComment( json.value( "comment", "" ) );
|
||||
if ( json.contains( "patterns" ) && json["patterns"].is_array() ) {
|
||||
const auto& patterns = json["patterns"];
|
||||
for ( const auto& pattern : patterns ) {
|
||||
std::vector<std::string> type;
|
||||
std::vector<std::string> endType;
|
||||
|
||||
if ( pattern.contains( "type" ) ) {
|
||||
if ( pattern["type"].is_array() ) {
|
||||
for ( const auto& t : pattern["type"] ) {
|
||||
if ( t.is_string() )
|
||||
type.push_back( t.get<std::string>() );
|
||||
}
|
||||
} else if ( pattern["type"].is_string() ) {
|
||||
type.push_back( pattern["type"] );
|
||||
}
|
||||
} else {
|
||||
type.push_back( "normal" );
|
||||
}
|
||||
|
||||
if ( pattern.contains( "end_type" ) ) {
|
||||
if ( pattern["end_type"].is_array() ) {
|
||||
for ( const auto& t : pattern["end_type"] ) {
|
||||
if ( t.is_string() )
|
||||
endType.push_back( t.get<std::string>() );
|
||||
}
|
||||
} else if ( pattern["end_type"].is_string() ) {
|
||||
endType.push_back( pattern["end_type"] );
|
||||
}
|
||||
}
|
||||
|
||||
auto syntax = !pattern.contains( "syntax" ) || !pattern["syntax"].is_string()
|
||||
? ""
|
||||
: pattern.value( "syntax", "" );
|
||||
std::vector<std::string> ptrns;
|
||||
auto ctype = SyntaxPatternMatchType::LuaPattern;
|
||||
if ( pattern.contains( "pattern" ) ) {
|
||||
if ( pattern["pattern"].is_array() ) {
|
||||
const auto& ptrnIt = pattern["pattern"];
|
||||
for ( const auto& ptrn : ptrnIt )
|
||||
ptrns.emplace_back( ptrn );
|
||||
} else if ( pattern["pattern"].is_string() ) {
|
||||
ptrns.emplace_back( pattern["pattern"] );
|
||||
}
|
||||
} else if ( pattern.contains( "regex" ) ) {
|
||||
ctype = SyntaxPatternMatchType::RegEx;
|
||||
if ( pattern["regex"].is_array() ) {
|
||||
const auto& ptrnIt = pattern["regex"];
|
||||
for ( const auto& ptrn : ptrnIt )
|
||||
ptrns.emplace_back( ptrn );
|
||||
} else if ( pattern["regex"].is_string() ) {
|
||||
ptrns.emplace_back( pattern["regex"] );
|
||||
}
|
||||
} else if ( pattern.contains( "parser" ) ) {
|
||||
ctype = SyntaxPatternMatchType::Parser;
|
||||
if ( pattern["parser"].is_array() ) {
|
||||
const auto& ptrnIt = pattern["parser"];
|
||||
for ( const auto& ptrn : ptrnIt )
|
||||
ptrns.emplace_back( ptrn );
|
||||
} else if ( pattern["parser"].is_string() ) {
|
||||
ptrns.emplace_back( pattern["parser"] );
|
||||
}
|
||||
}
|
||||
def.addPattern( SyntaxPattern( std::move( ptrns ), std::move( type ),
|
||||
std::move( endType ), syntax, ctype ) );
|
||||
}
|
||||
}
|
||||
if ( json.contains( "symbols" ) ) {
|
||||
if ( json["symbols"].is_array() ) {
|
||||
const auto& symbols = json["symbols"];
|
||||
@@ -520,6 +760,7 @@ static SyntaxDefinition loadLanguage( const nlohmann::json& json ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( json.contains( "headers" ) && json["headers"].is_array() ) {
|
||||
const auto& headers = json["headers"];
|
||||
std::vector<std::string> hds;
|
||||
@@ -529,17 +770,21 @@ static SyntaxDefinition loadLanguage( const nlohmann::json& json ) {
|
||||
hds.emplace_back( header.get<std::string>() );
|
||||
}
|
||||
} else if ( headers.is_string() ) {
|
||||
hds.push_back( headers.get<std::string>() );
|
||||
hds.emplace_back( headers.get<std::string>() );
|
||||
}
|
||||
if ( !hds.empty() )
|
||||
def.setHeaders( hds );
|
||||
}
|
||||
|
||||
if ( json.contains( "visible" ) && json["visible"].is_boolean() )
|
||||
def.setVisible( json["visible"].get<bool>() );
|
||||
|
||||
if ( json.contains( "auto_close_xml_tags" ) && json["auto_close_xml_tags"].is_boolean() )
|
||||
def.setAutoCloseXMLTags( json["auto_close_xml_tags"].get<bool>() );
|
||||
|
||||
if ( json.contains( "extension_priority" ) && json["extension_priority"].is_boolean() )
|
||||
def.setExtensionPriority( json["extension_priority"].get<bool>() );
|
||||
|
||||
if ( json.contains( "case_insensitive" ) && json["case_insensitive"].is_boolean() )
|
||||
def.setCaseInsensitive( json["case_insensitive"].get<bool>() );
|
||||
|
||||
@@ -566,6 +811,7 @@ static SyntaxDefinition loadLanguage( const nlohmann::json& json ) {
|
||||
} catch ( const json::exception& e ) {
|
||||
Log::error( "SyntaxDefinition loadLanguage failed:\n%s", e.what() );
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,19 @@
|
||||
#include <eepp/ui/doc/syntaxtokenizer.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <memory_resource>
|
||||
#include <variant>
|
||||
|
||||
using namespace EE::System;
|
||||
|
||||
namespace EE { namespace UI { namespace Doc {
|
||||
|
||||
struct PatternStackItem {
|
||||
const std::vector<SyntaxPattern>* patterns{ nullptr };
|
||||
size_t index = 0;
|
||||
Uint8 repositoryIdx = 0;
|
||||
};
|
||||
|
||||
// This tokenizer was a direct conversion to C++ from the lite (https://github.com/rxi/lite)
|
||||
// tokenizer. This allows eepp to support the same color schemes and syntax definitions from
|
||||
// lite. Making much easier to implement a complete code editor. Currently some improvements
|
||||
@@ -23,6 +30,8 @@ namespace EE { namespace UI { namespace Doc {
|
||||
|
||||
#define MAX_MATCHES ( 12 )
|
||||
|
||||
#define MAX_PATTERN_STACK_SIZE ( 16 )
|
||||
|
||||
static int isInMultiByteCodePoint( const char* text, const size_t& textSize, const size_t& pos ) {
|
||||
// current char is a multybyte codepoint
|
||||
if ( ( text[pos] & 0xC0 ) == 0x80 ) {
|
||||
@@ -293,7 +302,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
|
||||
if ( !words.isValid() ) // Skip invalid patterns
|
||||
return false;
|
||||
if ( words.matches( text, matches.data(), startIdx ) &&
|
||||
( numMatches = words.getNumMatches() ) > 0 ) {
|
||||
( numMatches = words.getNumMatches() ) > 0 && matches[0].start != matches[0].end ) {
|
||||
if ( shouldCloseSubSyntax ) {
|
||||
if ( shouldCloseSubSyntax->range.second >= matches[0].end ) {
|
||||
if ( !skipSubSyntaxSeparator ) {
|
||||
@@ -488,6 +497,13 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
|
||||
size_t size = text.size();
|
||||
size_t startIdx = startIndex;
|
||||
|
||||
static constexpr auto PATTERN_STACK_BUFFER =
|
||||
MAX_PATTERN_STACK_SIZE * sizeof( PatternStackItem );
|
||||
std::array<std::byte, PATTERN_STACK_BUFFER> patternStackBuffer;
|
||||
std::pmr::monotonic_buffer_resource patternStackRes(
|
||||
patternStackBuffer.data(), patternStackBuffer.size(), std::pmr::null_memory_resource() );
|
||||
std::pmr::vector<PatternStackItem> patternStack( &patternStackRes );
|
||||
|
||||
while ( startIdx < size ) {
|
||||
if ( curState.currentPatternIdx.state != SYNTAX_TOKENIZER_STATE_NONE ) {
|
||||
const SyntaxPattern& pattern =
|
||||
@@ -499,8 +515,8 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
|
||||
|
||||
bool skip = false;
|
||||
|
||||
if ( curState.subsyntaxInfo != nullptr &&
|
||||
curState.subsyntaxInfo->patterns.size() > 1 ) {
|
||||
if ( curState.subsyntaxInfo != nullptr && curState.subsyntaxInfo->patterns.size() > 1 &&
|
||||
curState.currentSyntax->getLanguageIndex() != syntax.getLanguageIndex() ) {
|
||||
auto rangeSubsyntax =
|
||||
findNonEscaped( text, curState.subsyntaxInfo->patterns[1], startIdx,
|
||||
curState.subsyntaxInfo->patterns.size() >= 3
|
||||
@@ -552,38 +568,43 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
|
||||
}
|
||||
}
|
||||
|
||||
patternStack.clear();
|
||||
patternStack.push_back( { &curState.currentSyntax->getPatterns(), 0, 0 } );
|
||||
bool matched = false;
|
||||
size_t patternsCount = curState.currentSyntax->getPatterns().size();
|
||||
|
||||
for ( size_t patternIndex = 0; patternIndex < patternsCount; patternIndex++ ) {
|
||||
const SyntaxPattern& pattern = curState.currentSyntax->getPatterns()[patternIndex];
|
||||
if ( startIdx != 0 && pattern.patterns[0][0] == '^' )
|
||||
while ( !patternStack.empty() && !matched ) {
|
||||
PatternStackItem& current = patternStack.back();
|
||||
if ( current.index >= current.patterns->size() ) {
|
||||
patternStack.pop_back();
|
||||
continue;
|
||||
}
|
||||
const SyntaxPattern* pattern = ¤t.patterns->data()[current.index];
|
||||
current.index++;
|
||||
|
||||
if ( pattern->isRepositoryInclude() ) {
|
||||
if ( patternStack.size() + 1 >= MAX_PATTERN_STACK_SIZE )
|
||||
break;
|
||||
|
||||
/*
|
||||
if ( pattern.isRepositoryInclude() ) {
|
||||
const auto& repo =
|
||||
curState.currentSyntax->getRepository( pattern.getRepositoryName() );
|
||||
size_t repoPatternCount = repo.size();
|
||||
for ( size_t repoPatternIndex = 0; repoPatternIndex < repoPatternCount;
|
||||
repoPatternIndex++ ) {
|
||||
curState.currentSyntax->getRepository( pattern->getRepositoryName() );
|
||||
patternStack.push_back(
|
||||
{ &repo, 0, static_cast<Uint8>( pattern->repositoryIdx ) } );
|
||||
} else if ( pattern->isRootSelfInclude() ) {
|
||||
if ( patternStack.size() + 1 >= MAX_PATTERN_STACK_SIZE )
|
||||
break;
|
||||
|
||||
if ( startIdx != 0 && repo[repoPatternIndex].patterns[0][0] == '^' )
|
||||
continue;
|
||||
patternStack.push_back( { &curState.currentSyntax->getPatterns(), 0, 0 } );
|
||||
} else {
|
||||
if ( startIdx != 0 && pattern->patterns[0][0] == '^' )
|
||||
continue;
|
||||
|
||||
if ( repo[repoPatternIndex].isPure() &&
|
||||
( matched =
|
||||
matchPattern( repo[repoPatternIndex], startIdx,
|
||||
{ static_cast<Uint8>( repoPatternIndex + 1 ),
|
||||
static_cast<Uint8>( pattern.repositoryIdx ) } ) ) )
|
||||
break;
|
||||
SyntaxStateType patternIndex = { static_cast<Uint8>( current.index ),
|
||||
current.repositoryIdx };
|
||||
if ( matchPattern( *pattern, startIdx, patternIndex ) ) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if ( ( matched = matchPattern( pattern, startIdx,
|
||||
{ static_cast<Uint8>( patternIndex + 1 ), 0 } ) ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !matched && shouldCloseSubSyntax ) {
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace EE { namespace UI { namespace Doc { namespace Language {
|
||||
|
||||
void addNim() {
|
||||
std::vector<SyntaxPattern> nim_patterns;
|
||||
UnorderedMap<std::string, std::string> nim_symbols;
|
||||
SyntaxDefMap<std::string, std::string> nim_symbols;
|
||||
|
||||
const std::vector<std::string> nim_number_patterns = {
|
||||
"0[bB][01][01_]*", "0o[0-7][0-7_]*",
|
||||
|
||||
@@ -3442,10 +3442,9 @@ bool App::needsRedirectToRunningProcess( std::string file ) {
|
||||
|
||||
void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDensity,
|
||||
const std::string& colorScheme, bool terminal, bool frameBuffer, bool benchmarkMode,
|
||||
std::string css, bool health, const std::string& healthLang,
|
||||
FeaturesHealth::OutputFormat healthFormat, const std::string& fileToOpen,
|
||||
bool stdOutLogs, bool disableFileLogs, bool openClean, bool portable,
|
||||
std::string language, bool incognito ) {
|
||||
std::string css, const std::string& fileToOpen, bool stdOutLogs,
|
||||
bool disableFileLogs, bool openClean, bool portable, std::string language,
|
||||
bool incognito, bool prematureExit ) {
|
||||
Http::setThreadPool( mThreadPool );
|
||||
DisplayManager* displayManager = Engine::instance()->getDisplayManager();
|
||||
Display* currentDisplay = displayManager->getDisplayIndex( 0 );
|
||||
@@ -3471,15 +3470,11 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
|
||||
mResPath += "assets";
|
||||
FileSystem::dirAddSlashAtEnd( mResPath );
|
||||
|
||||
bool firstRun =
|
||||
loadConfig( logLevel, currentDisplay->getSize(), health, stdOutLogs, disableFileLogs );
|
||||
bool firstRun = loadConfig( logLevel, currentDisplay->getSize(), prematureExit, stdOutLogs,
|
||||
disableFileLogs );
|
||||
|
||||
if ( health ) {
|
||||
Sys::windowAttachConsole();
|
||||
Language::LanguagesSyntaxHighlighting::load();
|
||||
FeaturesHealth::doHealth( mPluginManager.get(), healthLang, healthFormat );
|
||||
if ( prematureExit )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !openClean && needsRedirectToRunningProcess( file ) )
|
||||
return;
|
||||
@@ -4069,9 +4064,11 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
|
||||
}
|
||||
}
|
||||
|
||||
static void exportLanguages( const std::string& path, const std::string& langs ) {
|
||||
static void exportLanguages( const std::string& path, const std::string& langs,
|
||||
const std::string& langsPath ) {
|
||||
Language::LanguagesSyntaxHighlighting::load();
|
||||
SyntaxDefinitionManager* sdm = SyntaxDefinitionManager::instance();
|
||||
SyntaxDefinitionManager::instance()->loadFromFolder( langsPath );
|
||||
std::vector<SyntaxDefinition> defs;
|
||||
|
||||
if ( !langs.empty() ) {
|
||||
@@ -4243,12 +4240,6 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ( exportLangPath && !exportLangPath.Get().empty() ) {
|
||||
Sys::windowAttachConsole();
|
||||
exportLanguages( exportLangPath.Get(), exportLang.Get() );
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ( version.Get() ) {
|
||||
Sys::windowAttachConsole();
|
||||
std::cout << ecode::Version::getVersionFullName() << '\n';
|
||||
@@ -4264,9 +4255,26 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
appInstance->init( logLevel.Get(), folder ? folder.Get() : fileOrFolderPos.Get(),
|
||||
pixelDenstiyConf ? pixelDenstiyConf.Get() : 0.f,
|
||||
prefersColorScheme ? prefersColorScheme.Get() : "", terminal.Get(), fb.Get(),
|
||||
benchmarkMode.Get(), css.Get(), health || healthLang, healthLang.Get(),
|
||||
healthFormat.Get(), file.Get(), verbose.Get(), disableFileLogs.Get(),
|
||||
openClean.Get(), portable.Get(), language.Get(), incognito.Get() );
|
||||
benchmarkMode.Get(), css.Get(), file.Get(), verbose.Get(),
|
||||
disableFileLogs.Get(), openClean.Get(), portable.Get(), language.Get(),
|
||||
incognito.Get(),
|
||||
health || ( exportLangPath && !exportLangPath.Get().empty() ) );
|
||||
|
||||
if ( exportLangPath && !exportLangPath.Get().empty() ) {
|
||||
Sys::windowAttachConsole();
|
||||
exportLanguages( exportLangPath.Get(), exportLang.Get(), appInstance->getLanguagesPath() );
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ( health ) {
|
||||
Sys::windowAttachConsole();
|
||||
Language::LanguagesSyntaxHighlighting::load();
|
||||
SyntaxDefinitionManager::instance()->loadFromFolder( appInstance->getLanguagesPath() );
|
||||
FeaturesHealth::doHealth( appInstance->getPluginManager(), healthLang.Get(),
|
||||
healthFormat.Get() );
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
eeSAFE_DELETE( appInstance );
|
||||
|
||||
Engine::destroySingleton();
|
||||
|
||||
@@ -44,10 +44,9 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
|
||||
|
||||
void init( const LogLevel& logLevel, std::string file, const Float& pidelDensity,
|
||||
const std::string& colorScheme, bool terminal, bool frameBuffer, bool benchmarkMode,
|
||||
std::string css, bool health, const std::string& healthLang,
|
||||
ecode::FeaturesHealth::OutputFormat healthFormat, const std::string& fileToOpen,
|
||||
bool stdOutLogs, bool disableFileLogs, bool openClean, bool portable,
|
||||
std::string language, bool incognito );
|
||||
std::string css, const std::string& fileToOpen, bool stdOutLogs,
|
||||
bool disableFileLogs, bool openClean, bool portable, std::string language,
|
||||
bool incognito, bool prematureExit );
|
||||
|
||||
void createWidgetInspector();
|
||||
|
||||
@@ -492,6 +491,8 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
|
||||
|
||||
SettingsActions* getSettingsActions() { return mSettingsActions.get(); }
|
||||
|
||||
const std::string& getLanguagesPath() const { return mLanguagesPath; }
|
||||
|
||||
protected:
|
||||
std::vector<std::string> mArgs;
|
||||
EE::Window::Window* mWindow{ nullptr };
|
||||
|
||||
Reference in New Issue
Block a user