From ea8a44e7a96ed0573cacd9eda707fd95fd2d6c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 9 Mar 2025 13:37:33 -0300 Subject: [PATCH] Fixed an old bug in syntax highlighting that sometimes the first line of the file was not correctly highlighted. Added Svelte syntax highlighting support. Improved CSS syntax highlighting. Added "Open All Files in Folder" option when right click a folder in the folder tree view. --- include/eepp/ui/doc/textdocument.hpp | 1 + src/eepp/ui/doc/languages/css.cpp | 112 ++++++++++++++++++ src/eepp/ui/doc/syntaxhighlighter.cpp | 4 +- src/eepp/ui/doc/textdocument.cpp | 17 ++- src/eepp/ui/uicodeeditor.cpp | 3 +- .../src/eepp/ui/doc/languages/svelte.cpp | 72 +++++++++++ .../src/eepp/ui/doc/languages/svelte.hpp | 10 ++ .../ui/doc/languagessyntaxhighlighting.cpp | 2 + src/tools/ecode/ecode.cpp | 29 ++++- src/tools/ecode/ecode.hpp | 2 + src/tools/ecode/settingsmenu.cpp | 6 + 11 files changed, 251 insertions(+), 7 deletions(-) create mode 100644 src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.cpp create mode 100644 src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.hpp diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index 4ce4caa60..ff8df9fb3 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -713,6 +713,7 @@ class EE_API TextDocument { Client* mActiveClient{ nullptr }; mutable Mutex mLoadingMutex; mutable Mutex mLoadingFilePathMutex; + mutable Mutex mSyntaxDefinitionMutex; size_t mLastSelection{ 0 }; std::unique_ptr mHighlighter; Mutex mStopFlagsMutex; diff --git a/src/eepp/ui/doc/languages/css.cpp b/src/eepp/ui/doc/languages/css.cpp index aa4b92151..8f10c999d 100644 --- a/src/eepp/ui/doc/languages/css.cpp +++ b/src/eepp/ui/doc/languages/css.cpp @@ -264,6 +264,118 @@ void addCSS() { { "magenta", "literal" }, { "textinputpassword", "keyword" }, { "important", "literal" }, + { "a", "keyword" }, + { "abbr", "keyword" }, + { "address", "keyword" }, + { "area", "keyword" }, + { "article", "keyword" }, + { "aside", "keyword" }, + { "audio", "keyword" }, + { "b", "keyword" }, + { "base", "keyword" }, + { "bdi", "keyword" }, + { "bdo", "keyword" }, + { "blockquote", "keyword" }, + { "body", "keyword" }, + { "br", "keyword" }, + { "button", "keyword" }, + { "canvas", "keyword" }, + { "caption", "keyword" }, + { "cite", "keyword" }, + { "code", "keyword" }, + { "col", "keyword" }, + { "colgroup", "keyword" }, + { "data", "keyword" }, + { "datalist", "keyword" }, + { "dd", "keyword" }, + { "del", "keyword" }, + { "details", "keyword" }, + { "dfn", "keyword" }, + { "dialog", "keyword" }, + { "div", "keyword" }, + { "dl", "keyword" }, + { "dt", "keyword" }, + { "em", "keyword" }, + { "embed", "keyword" }, + { "fieldset", "keyword" }, + { "figcaption", "keyword" }, + { "figure", "keyword" }, + { "footer", "keyword" }, + { "form", "keyword" }, + { "h1", "keyword" }, + { "h2", "keyword" }, + { "h3", "keyword" }, + { "h4", "keyword" }, + { "h5", "keyword" }, + { "h6", "keyword" }, + { "head", "keyword" }, + { "header", "keyword" }, + { "hr", "keyword" }, + { "html", "keyword" }, + { "i", "keyword" }, + { "iframe", "keyword" }, + { "img", "keyword" }, + { "input", "keyword" }, + { "ins", "keyword" }, + { "kbd", "keyword" }, + { "label", "keyword" }, + { "legend", "keyword" }, + { "li", "keyword" }, + { "link", "keyword" }, + { "main", "keyword" }, + { "map", "keyword" }, + { "mark", "keyword" }, + { "menu", "keyword" }, + { "meta", "keyword" }, + { "meter", "keyword" }, + { "nav", "keyword" }, + { "noscript", "keyword" }, + { "object", "keyword" }, + { "ol", "keyword" }, + { "optgroup", "keyword" }, + { "option", "keyword" }, + { "output", "keyword" }, + { "p", "keyword" }, + { "param", "keyword" }, + { "picture", "keyword" }, + { "pre", "keyword" }, + { "progress", "keyword" }, + { "q", "keyword" }, + { "rp", "keyword" }, + { "rt", "keyword" }, + { "ruby", "keyword" }, + { "s", "keyword" }, + { "samp", "keyword" }, + { "script", "keyword" }, + { "section", "keyword" }, + { "select", "keyword" }, + { "slot", "keyword" }, + { "small", "keyword" }, + { "source", "keyword" }, + { "span", "keyword" }, + { "strong", "keyword" }, + { "style", "keyword" }, + { "sub", "keyword" }, + { "summary", "keyword" }, + { "sup", "keyword" }, + { "table", "keyword" }, + { "tbody", "keyword" }, + { "td", "keyword" }, + { "template", "keyword" }, + { "textarea", "keyword" }, + { "tfoot", "keyword" }, + { "th", "keyword" }, + { "thead", "keyword" }, + { "time", "keyword" }, + { "title", "keyword" }, + { "tr", "keyword" }, + { "track", "keyword" }, + { "u", "keyword" }, + { "ul", "keyword" }, + { "var", "keyword" }, + { "video", "keyword" }, + { "wbr", "keyword" }, + { "Widget", "keyword" }, { "LinearLayout", "keyword" }, { "RelativeLayout", "keyword" }, diff --git a/src/eepp/ui/doc/syntaxhighlighter.cpp b/src/eepp/ui/doc/syntaxhighlighter.cpp index 9a46f823b..5388b0976 100644 --- a/src/eepp/ui/doc/syntaxhighlighter.cpp +++ b/src/eepp/ui/doc/syntaxhighlighter.cpp @@ -199,8 +199,8 @@ Int64 SyntaxHighlighter::getMaxWantedLine() const { } bool SyntaxHighlighter::updateDirty( int visibleLinesCount ) { - if ( visibleLinesCount <= 0 ) - return 0; + if ( visibleLinesCount <= 0 || mTokenizeAsync ) + return false; if ( mFirstInvalidLine > mMaxWantedLine ) { mMaxWantedLine = 0; } else { diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 6effb81f0..a47993c05 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -100,7 +100,10 @@ void TextDocument::reset() { mLastSelection = 0; mLines.clear(); mLines.emplace_back( String( "\n" ) ); - mSyntaxDefinition = SyntaxDefinitionManager::instance()->getPlainDefinition(); + { + Lock l( mSyntaxDefinitionMutex ); + mSyntaxDefinition = SyntaxDefinitionManager::instance()->getPlainDefinition(); + } mUndoStack.clear(); cleanChangeId(); notifySyntaxDefinitionChange(); @@ -403,6 +406,7 @@ void TextDocument::mergeSelection() { } bool TextDocument::hasSyntaxDefinition() const { + Lock l( mSyntaxDefinitionMutex ); return !mSyntaxDefinition.getPatterns().empty(); } @@ -414,7 +418,10 @@ const SyntaxDefinition& TextDocument::guessSyntax() const { void TextDocument::resetSyntax() { String header( getText( { { 0, 0 }, positionOffset( { 0, 0 }, 128 ) } ) ); std::string oldDef = mSyntaxDefinition.getLSPName(); - mSyntaxDefinition = SyntaxDefinitionManager::instance()->find( mFilePath, header, mHAsCpp ); + { + Lock l( mSyntaxDefinitionMutex ); + mSyntaxDefinition = SyntaxDefinitionManager::instance()->find( mFilePath, header, mHAsCpp ); + } if ( mSyntaxDefinition.getLSPName() != oldDef ) notifySyntaxDefinitionChange(); } @@ -2421,12 +2428,16 @@ void TextDocument::redo() { } const SyntaxDefinition& TextDocument::getSyntaxDefinition() const { + Lock l( mSyntaxDefinitionMutex ); return mSyntaxDefinition; } void TextDocument::setSyntaxDefinition( const SyntaxDefinition& definition ) { if ( mSyntaxDefinition.getLSPName() != definition.getLSPName() ) { - mSyntaxDefinition = definition; + { + Lock l( mSyntaxDefinitionMutex ); + mSyntaxDefinition = definition; + } notifySyntaxDefinitionChange(); } } diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 55c5945e9..51f13fb3e 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -448,7 +448,8 @@ void UICodeEditor::scheduledUpdate( const Time& ) { if ( !mVisible ) return; - if ( mDoc && !mDoc->isLoading() && + if ( mDoc && !mDoc->isLoading() && !mDoc->isEmpty() && + !mDoc->getSyntaxDefinition().getPatterns().empty() && mDoc->getHighlighter()->updateDirty( getVisibleLinesCount() ) ) { invalidateDraw(); } diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.cpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.cpp new file mode 100644 index 000000000..6ada658cb --- /dev/null +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.cpp @@ -0,0 +1,72 @@ +#include +#include + +namespace EE { namespace UI { namespace Doc { namespace Language { + +void addSvelte() { + + SyntaxDefinitionManager::instance() + ->add( + + { "Svelte", + { "%.svelte$" }, + { + { { "<%s*[sS][cC][rR][iI][pP][tT]%s+[tT][yY][pP][eE]%s*=%s*['\"]%a+/" + "[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]['\"]%s*>", + "<%s*/[sS][cC][rR][iI][pP][tT]>" }, + "function", + "JavaScript" }, + { { "<%s*[sS][cC][rR][iI][pP][tT]%s+([lL][aA][nN][gG])%s*(=)%s*(['\"][tT][sS]['" + "\"])%s*>", + "<%s*/[sS][cC][rR][iI][pP][tT]>" }, + { "function", "keyword", "operator", "string" }, + "TypeScript" }, + { { "<%s*[sS][cC][rR][iI][pP][tT]%s*>", "<%s*/%s*[sS][cC][rR][iI][pP][tT]>" }, + "function", + "JavaScript" }, + { { "<%s*[sS][tT][yY][lL][eE][^>]*>", "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" }, + "function", + "CSS" }, + { { "" }, "comment" }, + { { "\"", "\"", "\\" }, "string" }, + { { "'", "'", "\\" }, "string" }, + { { "{@html[^}]*}" }, "keyword", "", true }, + { { "{@debug[^}]*}" }, "keyword", "", true }, + { { "{(:else|:then|:catch)}" }, + std::vector{ "keyword", "keyword2" }, + "", + true }, + { { "{(/if|/each|/await|/key)}" }, + std::vector{ "keyword", "keyword2" }, + "", + true }, + { { "{(#if|#each|#await|#key)", "}", "\\" }, + { "keyword", "keyword2", "normal" }, + "JavaScript", + true }, + { { "{", "}", "\\" }, "keyword", "JavaScript" }, + { { "([%a_][%w_-]*)(:)([%a_][%w_-]*)(=)" }, + { "keyword", "keyword2", "normal", "keyword", "operator" } }, + { { "([%a_][%w_-]*)(=)" }, { "keyword", "keyword", "operator" } }, + { { "0x[%da-fA-F]+" }, "number" }, + { { "-?%d+[%d%.]*f?" }, "number" }, + { { "-?%.?%d+f?" }, "number" }, + { { "%f[^<][%a_][%w%_%-]*(:)([%w_-]+)" }, { "function", "normal", "keyword" } }, + { { "%f[^<]/[%a_][%w%_%-]*(:)([%w_-]+)" }, { "function", "normal", "keyword" } }, + { { "%f[^<]![%a_][%w%_%-]*" }, "keyword2" }, + { { "%f[^<][%a_][%w%_%-]*" }, "function" }, + { { "%f[^<]/[%a_][%w%_%-]*" }, "function" }, + { { "[/<>=]" }, "operator" }, + + }, + { + + }, + "", + {} + + } ) + .setAutoCloseXMLTags( true ); +} + +}}}} // namespace EE::UI::Doc::Language diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.hpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.hpp new file mode 100644 index 000000000..4cb1dabb4 --- /dev/null +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.hpp @@ -0,0 +1,10 @@ +#ifndef EE_UI_DOC_Svelte +#define EE_UI_DOC_Svelte + +namespace EE { namespace UI { namespace Doc { namespace Language { + +extern void addSvelte(); + +}}}} // namespace EE::UI::Doc::Language + +#endif diff --git a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp index 1767f6f1b..7b5c65078 100644 --- a/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp +++ b/src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -163,6 +164,7 @@ void LanguagesSyntaxHighlighting::load() { addSmallBASIC(); addSolidity(); addSQL(); + addSvelte(); addSwift(); addTeal(); addToml(); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 35b2a8ce4..a2b734874 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -2767,6 +2767,33 @@ void App::renameFile( const FileInfo& file ) { } ); } +void App::openAllFilesInFolder( const FileInfo& folder ) { + auto files = + FileSystem::filesInfoGetInPath( folder.getDirectoryPath(), true, false, true, + getFileSystemModel()->getDisplayConfig().ignoreHidden ); + + std::vector supportedExts( + SyntaxDefinitionManager::instance()->getExtensionsPatternsSupported() ); + std::vector acceptedPatterns; + acceptedPatterns.reserve( supportedExts.size() ); + for ( const auto& strPattern : supportedExts ) + acceptedPatterns.emplace_back( std::string{ strPattern } ); + + for ( const auto& file : files ) { + if ( file.isRegularFile() ) { + bool foundPattern = acceptedPatterns.empty(); + for ( auto& pattern : acceptedPatterns ) { + if ( pattern.matches( file.getFilepath() ) ) { + foundPattern = true; + break; + } + } + if ( foundPattern ) + loadFileFromPath( file.getFilepath() ); + } + } +} + void App::toggleHiddenFiles() { mFileSystemModel = FileSystemModel::New( mFileSystemModel->getRootPath(), FileSystemModel::Mode::FilesAndDirectories, @@ -3497,7 +3524,7 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe mThreadPool->run( [this] { // Load language definitions Clock defClock; - SyntaxDefinitionManager::createSingleton( 107 ); + SyntaxDefinitionManager::createSingleton( 108 ); Language::LanguagesSyntaxHighlighting::load(); SyntaxDefinitionManager::instance()->setLanguageExtensionsPriority( mConfig.languagesExtensions.priorities ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 6a0039ed2..7f6122b12 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -390,6 +390,8 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { void renameFile( const FileInfo& file ); + void openAllFilesInFolder( const FileInfo& folder ); + UIMessageBox* newInputMsgBox( const String& title, const String& msg ); std::string getNewFilePath( const FileInfo& file, UIMessageBox* msgBox, bool keepDir = true ); diff --git a/src/tools/ecode/settingsmenu.cpp b/src/tools/ecode/settingsmenu.cpp index 1bd1d89f2..7515366b9 100644 --- a/src/tools/ecode/settingsmenu.cpp +++ b/src/tools/ecode/settingsmenu.cpp @@ -2153,6 +2153,10 @@ void SettingsMenu::createProjectTreeMenu( const FileInfo& file ) { mProjectTreeMenu ->add( i18n( "open_folder_ellipsis", "Open Folder..." ), findIcon( "folder-open" ) ) ->setId( "open_folder" ); + mProjectTreeMenu + ->add( i18n( "open_all_files_in_folder", "Open All Files in Folder" ), + findIcon( "folder-open" ) ) + ->setId( "open_all_files_in_folder" ); } else { if ( file.isRegularFile() ) { auto curDir( mApp->getCurrentWorkingDir() ); @@ -2260,6 +2264,8 @@ void SettingsMenu::createProjectTreeMenu( const FileInfo& file ) { Engine::instance()->openURI( file.getDirectoryPath() ); } else if ( "open_folder" == id ) { Engine::instance()->openURI( file.getFilepath() ); + } else if ( "open_all_files_in_folder" == id ) { + mApp->openAllFilesInFolder( file ); } else if ( "show-hidden-files" == id ) { mApp->toggleHiddenFiles(); } else if ( "execute_in_terminal" == id ) {