From 893e3cd9120c94fe16e7e49c931c1faad314a7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Wed, 4 Oct 2023 20:30:28 -0300 Subject: [PATCH] Allow selecting and copying text in UIConsole. IniFile detects BOM headers. Fix small bug when opening ecode logs. --- include/eepp/ui/doc/textrange.hpp | 4 + include/eepp/ui/uiconsole.hpp | 26 ++ src/eepp/system/inifile.cpp | 8 + src/eepp/ui/doc/textdocument.cpp | 2 +- src/eepp/ui/uiconsole.cpp | 279 ++++++++++++++++-- src/tools/ecode/ecode.cpp | 8 +- src/tools/ecode/ecode.hpp | 1 + src/tools/ecode/filesystemlistener.cpp | 12 +- src/tools/ecode/filesystemlistener.hpp | 6 +- .../plugins/formatter/formatterplugin.cpp | 1 - 10 files changed, 315 insertions(+), 32 deletions(-) diff --git a/include/eepp/ui/doc/textrange.hpp b/include/eepp/ui/doc/textrange.hpp index 70af8318a..e5bcbacc2 100644 --- a/include/eepp/ui/doc/textrange.hpp +++ b/include/eepp/ui/doc/textrange.hpp @@ -97,6 +97,10 @@ class EE_API TextRange { return true; } + bool containsLine( const Int64& line ) const { + return line >= mStart.line() && line <= mEnd.line(); + } + bool contains( const TextRange& range ) const { return range.start() >= start() && range.end() <= end(); } diff --git a/include/eepp/ui/uiconsole.hpp b/include/eepp/ui/uiconsole.hpp index acb885912..c418c39ae 100644 --- a/include/eepp/ui/uiconsole.hpp +++ b/include/eepp/ui/uiconsole.hpp @@ -15,6 +15,9 @@ using namespace EE::UI::Doc; namespace EE { namespace UI { +class UIPopUpMenu; +class UIMenuItem; + class EE_API UIConsole : public UIWidget, protected LogReaderInterface, public TextDocument::Client { @@ -130,6 +133,10 @@ class EE_API UIConsole : public UIWidget, void setBlinkTime( const Time& blinkTime ); + size_t getMenuIconSize() const; + + void setMenuIconSize( size_t menuIconSize ); + protected: struct TextCache { Text text; @@ -148,6 +155,7 @@ class EE_API UIConsole : public UIWidget, Uint32 mMaxLogLines{ 8192 }; TextDocument mDoc; KeyBindings mKeyBindings; + TextRange mSelection; struct sCon { int min{ 0 }; @@ -173,6 +181,8 @@ class EE_API UIConsole : public UIWidget, Float mQuakeModeHeightPercent{ 0.6f }; #endif Uint64 mLastExecuteEventId{ 0 }; + UIPopUpMenu* mCurrentMenu{ nullptr }; + size_t mMenuIconSize{ 16 }; UIConsole( Font* Font, const bool& makeDefaultCommands = true, const bool& attachToLog = true, const unsigned int& maxLogLines = 1024 ); @@ -194,6 +204,10 @@ class EE_API UIConsole : public UIWidget, virtual Uint32 onMouseDown( const Vector2i& position, const Uint32& flags ); + virtual Uint32 onMouseMove( const Vector2i& position, const Uint32& flags ); + + virtual Uint32 onMouseDoubleClick( const Vector2i& position, const Uint32& flags ); + virtual Uint32 onMouseUp( const Vector2i& position, const Uint32& flags ); virtual Uint32 onFocus(); @@ -216,6 +230,8 @@ class EE_API UIConsole : public UIWidget, virtual void onDocumentMoved( TextDocument* ); + virtual bool onCreateContextMenu( const Vector2i& position, const Uint32& flags ); + void onDocumentClosed( TextDocument* ){}; void onDocumentDirtyOnFileSystem( TextDocument* ){}; @@ -298,6 +314,16 @@ class EE_API UIConsole : public UIWidget, Int32 maxLinesOnScreen(); void updateQuakeMode(); + + TextPosition getPositionOnScreen( Vector2f position ); + + UIMenuItem* menuAdd( UIPopUpMenu* menu, const std::string& translateKey, + const String& translateString, const std::string& icon, + const std::string& cmd ); + + Drawable* findIcon( const std::string& name ); + + void copySelection(); }; }} // namespace EE::UI diff --git a/src/eepp/system/inifile.cpp b/src/eepp/system/inifile.cpp index 648dff24d..21d8dac27 100644 --- a/src/eepp/system/inifile.cpp +++ b/src/eepp/system/inifile.cpp @@ -91,8 +91,16 @@ bool IniFile::readFile() { if ( mIniReaded ) return true; + bool isBOM = false; + if ( mBuffer.size() >= 3 && (char)0xef == mBuffer[0] && (char)0xbb == mBuffer[1] && + (char)0xbf == mBuffer[2] ) { + isBOM = true; + } + // ini_parse_string( mBuffer.c_str(), ValueHandler, this ); std::string_view buffer( mBuffer ); + if ( isBOM ) + buffer = std::string_view( mBuffer.data() + 3, mBuffer.size() - 3 ); std::string_view line; std::string_view keyname, valuename, value; std::string::size_type pLeft, pRight; diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 27bd2be37..c9a8384cc 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -22,7 +22,7 @@ namespace EE { namespace UI { namespace Doc { // Text document is loosely based on the SerenityOS (https://github.com/SerenityOS/serenity) // TextDocument and the lite editor (https://github.com/rxi/lite) implementations. -const char DEFAULT_NON_WORD_CHARS[] = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"; +static constexpr char DEFAULT_NON_WORD_CHARS[] = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"; bool TextDocument::isNonWord( String::StringBaseType ch ) const { return mNonWordChars.find_first_of( ch ) != String::InvalidPos; diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp index 1b760f9fb..c5421e00b 100644 --- a/src/eepp/ui/uiconsole.cpp +++ b/src/eepp/ui/uiconsole.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,10 +41,10 @@ UIConsole::UIConsole( Font* font, const bool& makeDefaultCommands, const bool& a const unsigned int& maxLogLines ) : UIWidget( "console" ), mKeyBindings( getUISceneNode()->getWindow()->getInput() ) { setFlags( UI_AUTO_PADDING ); - mFlags |= UI_TAB_STOP | UI_SCROLLABLE; + mFlags |= UI_TAB_STOP | UI_SCROLLABLE | UI_TEXT_SELECTION_ENABLED; setClipType( ClipType::ContentBox ); - setBackgroundColor( 0x201F1FEE ); + setBackgroundColor( 0x201F1F11 ); mDoc.registerClient( this ); registerCommands(); @@ -58,6 +60,8 @@ UIConsole::UIConsole( Font* font, const bool& makeDefaultCommands, const bool& a Log::error( "A monospace font must be loaded to be able to use the console.\nTry loading " "a font with the name \"monospace\"" ); + setFontSelectionBackColor( 0x4d668066 ); + if ( makeDefaultCommands ) createDefaultCommands(); @@ -127,6 +131,14 @@ void UIConsole::setBlinkTime( const Time& blinkTime ) { } } +size_t UIConsole::getMenuIconSize() const { + return mMenuIconSize; +} + +void UIConsole::setMenuIconSize( size_t menuIconSize ) { + mMenuIconSize = menuIconSize; +} + Font* UIConsole::getFont() const { return mFontStyleConfig.Font; } @@ -377,7 +389,8 @@ void UIConsole::setMaxLogLines( const Uint32& maxLogLines ) { void UIConsole::privPushText( const String& str ) { Lock l( mMutex ); mCmdLog.push_back( { str, String::hash( str ) } ); - invalidateDraw(); + if ( mVisible ) + invalidateDraw(); if ( mCmdLog.size() >= mMaxLogLines ) mCmdLog.pop_front(); } @@ -415,30 +428,84 @@ void UIConsole::draw() { mFontStyleConfig.FontColor.b ) .blendAlpha( (Uint8)mAlpha ) ); - for ( int i = mCon.max - mCon.modif; i >= mCon.min - mCon.modif; i-- ) { - if ( i < (int)mCmdLog.size() && i >= 0 ) { - curY = mScreenPos.y + getPixelsSize().getHeight() - mPaddingPx.Bottom - - pos * lineHeight - lineHeight * 2 - 1; - Text& text = mTextCache[pos].text; - text.setStyleConfig( mFontStyleConfig ); - text.setFillColor( fontColor ); - if ( mCmdLog[i].hash != mTextCache[pos].hash ) { - if ( mCmdLog[i].log.size() * cw <= mSize.getWidth() ) { - text.setString( mCmdLog[i].log ); - mTextCache[pos].hash = mCmdLog[i].hash; - } else { - auto substr = mCmdLog[i].log.substr( 0, ( mSize.getWidth() + 8 * cw ) / cw ); - mTextCache[pos].hash = String::hash( substr ); - text.setString( substr ); - } + Primitives p; + p.setColor( mFontStyleConfig.FontSelectionBackColor.blendAlpha( (Uint8)mAlpha ) ); + auto to = eemax( mCon.min - mCon.modif, 0 ); + auto from = eemin( mCon.max - mCon.modif, (int)mCmdLog.size() - 1 ); + + for ( int i = from; i >= to; i-- ) { + curY = mScreenPos.y + getPixelsSize().getHeight() - mPaddingPx.Bottom - pos * lineHeight - + lineHeight * 2 - 1; + + auto selNorm = mSelection.normalized(); + if ( mSelection.isValid() && mSelection.hasSelection() && selNorm.containsLine( i ) && + i < (int)mCmdLog.size() ) { + auto startCol = eemin( (Int64)mCmdLog[i].log.size(), selNorm.start().column() ); + auto endCol = eemin( (Int64)mCmdLog[i].log.size(), selNorm.end().column() ); + + if ( i == selNorm.start().line() ) { + auto tsubstr = mCmdLog[i].log.view().substr( + startCol, selNorm.end().line() == i ? eemax( (Int64)0, endCol - startCol ) + : (Int64)mCmdLog[i].log.size() - startCol ); + auto twidth = + Text::getTextWidth( mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + tsubstr, mFontStyleConfig.Style ); + auto fsubstr = mCmdLog[i].log.view().substr( 0, startCol ); + auto fwidth = + Text::getTextWidth( mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + fsubstr, mFontStyleConfig.Style ); + p.drawRectangle( Rectf( { mScreenPos.x + mPaddingPx.Left + fwidth, curY }, + { twidth, lineHeight } ) ); + } else if ( i == selNorm.end().line() ) { + auto fsubstr = mCmdLog[i].log.view().substr( 0, endCol ); + auto fwidth = + Text::getTextWidth( mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + fsubstr, mFontStyleConfig.Style ); + p.drawRectangle( + Rectf( { mScreenPos.x + mPaddingPx.Left, curY }, { fwidth, lineHeight } ) ); + } else { + p.drawRectangle( + Rectf( { mScreenPos.x + mPaddingPx.Left, curY }, + { getPixelsSize().getWidth() - mPadding.getWidth(), lineHeight } ) ); } - text.draw( mScreenPos.x + mPaddingPx.Left, curY ); - pos++; + + p.setForceDraw( true ); } + + Text& text = mTextCache[pos].text; + text.setStyleConfig( mFontStyleConfig ); + text.setFillColor( fontColor ); + if ( mCmdLog[i].hash != mTextCache[pos].hash ) { + if ( mCmdLog[i].log.size() * cw <= mSize.getWidth() ) { + text.setString( mCmdLog[i].log ); + mTextCache[pos].hash = mCmdLog[i].hash; + } else { + auto substr = mCmdLog[i].log.substr( 0, ( mSize.getWidth() + 8 * cw ) / cw ); + mTextCache[pos].hash = String::hash( substr ); + text.setString( substr ); + } + } + text.draw( mScreenPos.x + mPaddingPx.Left, curY ); + pos++; } curY = mScreenPos.y + getPixelsSize().getHeight() - mPaddingPx.Bottom - lineHeight - 1; + if ( mDoc.hasSelection() ) { + auto mwidth = Text::getTextWidth( mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + String( "> " ), mFontStyleConfig.Style ); + auto sel = mDoc.getSelection( true ); + auto tsubstr = mDoc.getCurrentLine().getText().view().substr( 0, sel.start().column() ); + auto twidth = Text::getTextWidth( mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + tsubstr, mFontStyleConfig.Style ); + auto fsubstr = mDoc.getCurrentLine().getText().view().substr( sel.start().column(), + sel.end().column() ); + auto fwidth = Text::getTextWidth( mFontStyleConfig.Font, mFontStyleConfig.CharacterSize, + fsubstr, mFontStyleConfig.Style ); + p.drawRectangle( Rectf( { mScreenPos.x + mPaddingPx.Left + mwidth + twidth, curY }, + { fwidth, lineHeight } ) ); + } + Text& text = mTextCache[mTextCache.size() - 1].text; text.setStyleConfig( mFontStyleConfig ); text.setFillColor( fontColor ); @@ -846,8 +913,15 @@ Uint32 UIConsole::onPressEnter() { invalidateDraw(); return 0; } + void UIConsole::registerCommands() { - mDoc.setCommand( "copy", [this] { copy(); } ); + mDoc.setCommand( "copy", [this] { + if ( mSelection.hasSelection() ) { + copySelection(); + } else { + copy(); + } + } ); mDoc.setCommand( "cut", [this] { cut(); } ); mDoc.setCommand( "paste", [this] { paste(); } ); mDoc.setCommand( "press-enter", [this] { onPressEnter(); } ); @@ -916,6 +990,22 @@ bool UIConsole::isTextSelectionEnabled() const { return 0 != ( mFlags & UI_TEXT_SELECTION_ENABLED ); } +TextPosition UIConsole::getPositionOnScreen( Vector2f position ) { + convertToNodeSpace( position ); + Float lineHeight = getLineHeight(); + auto linesInScreen = linesOnScreen(); + auto firstVisibleLine = eemax( mCon.min - mCon.modif, 0 ); + Float startOffset = + getPixelsSize().getHeight() - mPaddingPx.Bottom - linesInScreen * lineHeight; + Int64 line = eeclamp( (Int64)0, (Int64)eefloor( ( position.y - startOffset ) / lineHeight + 1 ), + (Int64)mCmdLog.size() - 1 ); + Int64 fline = eeclamp( (Int64)0, firstVisibleLine + line, (Int64)mCmdLog.size() - 1 ); + Int64 col = Text::findCharacterFromPos( + { (int)eefloor( position.x - mPaddingPx.Left ), 0 }, true, mFontStyleConfig.Font, + mFontStyleConfig.CharacterSize, mCmdLog[fline].log, mFontStyleConfig.Style ); + return { fline, col }; +} + Uint32 UIConsole::onMouseDown( const Vector2i& position, const Uint32& flags ) { UIWidget::onMouseDown( position, flags ); @@ -923,6 +1013,55 @@ Uint32 UIConsole::onMouseDown( const Vector2i& position, const Uint32& flags ) { getEventDispatcher()->getMouseDownNode() == this && !mMouseDown ) { getUISceneNode()->getWindow()->getInput()->captureMouse( true ); mMouseDown = true; + auto pos = getPositionOnScreen( position.asFloat() ); + auto prevSelection = mSelection; + mSelection = { pos, pos }; + if ( prevSelection != mSelection ) + invalidateDraw(); + } + + return 1; +} + +Uint32 UIConsole::onMouseMove( const Vector2i& position, const Uint32& flags ) { + UIWidget::onMouseMove( position, flags ); + + if ( ( flags & EE_BUTTON_LMASK ) && getEventDispatcher()->getMouseDownNode() == this && + mMouseDown ) { + auto prevSelection = mSelection; + mSelection.setEnd( getPositionOnScreen( position.asFloat() ) ); + if ( prevSelection != mSelection ) + invalidateDraw(); + } + + return 1; +} + +static constexpr char DEFAULT_NON_WORD_CHARS[] = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"; + +Uint32 UIConsole::onMouseDoubleClick( const Vector2i& position, const Uint32& flags ) { + UIWidget::onMouseDoubleClick( position, flags ); + + if ( ( flags & EE_BUTTON_LMASK ) ) { + auto pos = getPositionOnScreen( position.asFloat() ); + if ( pos.line() < (Int64)mCmdLog.size() ) { + const String& str = mCmdLog[pos.line()].log; + if ( pos.column() < (Int64)str.size() ) { + auto start = str.find_last_of( DEFAULT_NON_WORD_CHARS, pos.column() ); + auto end = str.find_first_of( DEFAULT_NON_WORD_CHARS, pos.column() ); + if ( start == String::InvalidPos ) + start = 0; + else + start = eemin( start + 1, str.size() - 1 ); + if ( end == String::InvalidPos ) + end = str.size(); + auto prevSelection = mSelection; + mSelection = { { pos.line(), static_cast( start ) }, + { pos.line(), static_cast( end ) } }; + if ( prevSelection != mSelection ) + invalidateDraw(); + } + } } return 1; @@ -947,7 +1086,7 @@ Uint32 UIConsole::onMouseUp( const Vector2i& position, const Uint32& flags ) { getUISceneNode()->getWindow()->getInput()->captureMouse( false ); } } else if ( ( flags & EE_BUTTON_RMASK ) ) { - // onCreateContextMenu( position, flags ); + onCreateContextMenu( position, flags ); } return UIWidget::onMouseUp( position, flags ); } @@ -985,6 +1124,100 @@ void UIConsole::onDocumentSaved( TextDocument* ) {} void UIConsole::onDocumentMoved( TextDocument* ) {} +Drawable* UIConsole::findIcon( const std::string& name ) { + UIIcon* icon = getUISceneNode()->findIcon( name ); + if ( icon ) + return icon->getSize( mMenuIconSize ); + return nullptr; +} + +void UIConsole::copySelection() { + std::string str; + auto selNorm = mSelection.normalized(); + + for ( Int64 i = selNorm.start().line(); i <= selNorm.end().line(); i++ ) { + auto startCol = eemin( (Int64)mCmdLog[i].log.size(), selNorm.start().column() ); + auto endCol = eemin( (Int64)mCmdLog[i].log.size(), selNorm.end().column() ); + + if ( i >= (Int64)mCmdLog.size() ) + continue; + + if ( i == selNorm.start().line() ) { + str += mCmdLog[i] + .log + .substr( startCol, selNorm.end().line() == i + ? eemax( (Int64)0, endCol - startCol ) + : (Int64)mCmdLog[i].log.size() - startCol ) + .toUtf8(); + if ( endCol == (Int64)mCmdLog[i].log.size() ) + str += "\n"; + } else if ( i == selNorm.end().line() ) { + str += mCmdLog[i].log.substr( 0, endCol ).toUtf8(); + if ( endCol == (Int64)mCmdLog[i].log.size() ) + str += "\n"; + } else { + str += mCmdLog[i].log.toUtf8(); + str += "\n"; + } + } + + getUISceneNode()->getWindow()->getClipboard()->setText( str ); +} + +UIMenuItem* UIConsole::menuAdd( UIPopUpMenu* menu, const std::string& translateKey, + const String& translateString, const std::string& icon, + const std::string& cmd ) { + UIMenuItem* menuItem = + menu->add( getTranslatorString( "@string/uiconsole_" + translateKey, translateString ), + findIcon( icon ), mKeyBindings.getCommandKeybindString( cmd ) ); + menuItem->setId( cmd ); + return menuItem; +} + +bool UIConsole::onCreateContextMenu( const Vector2i& position, const Uint32& flags ) { + if ( mCurrentMenu ) + return false; + + UIPopUpMenu* menu = UIPopUpMenu::New(); + + menuAdd( menu, "copy", "Copy", "copy", "copy" )->setEnabled( mSelection.hasSelection() ); + + ContextMenuEvent event( this, menu, Event::OnCreateContextMenu, position, flags ); + sendEvent( &event ); + + if ( menu->getCount() == 0 ) { + menu->close(); + return false; + } + + menu->setCloseOnHide( true ); + menu->addEventListener( Event::OnItemClicked, [&, menu]( const Event* event ) { + if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) + return; + UIMenuItem* item = event->getNode()->asType(); + const std::string& txt( item->getId() ); + if ( txt == "copy" ) + copySelection(); + menu->hide(); + } ); + + Vector2f pos( position.asFloat() ); + runOnMainThread( [this, menu, pos]() { + Vector2f npos( pos ); + menu->nodeToWorldTranslation( npos ); + UIMenu::findBestMenuPos( npos, menu ); + menu->setPixelsPosition( npos ); + menu->show(); + mCurrentMenu = menu; + } ); + menu->addEventListener( Event::OnMenuHide, [this]( const Event* ) { + if ( !isClosing() ) + setFocus(); + } ); + menu->addEventListener( Event::OnClose, [this]( const Event* ) { mCurrentMenu = nullptr; } ); + return true; +} + void UIConsole::onSelectionChange() { invalidateDraw(); } diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index f474b1296..6cdb0c6c6 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -471,10 +471,12 @@ bool App::loadConfig( const LogLevel& logLevel, const Sizeu& displaySize, bool s FileSystem::makeDir( mThemesPath ); FileSystem::dirAddSlashAtEnd( mThemesPath ); + mLogsPath = mConfigPath + "ecode.log"; + #ifndef EE_DEBUG - Log::create( mConfigPath + "ecode.log", logLevel, stdOutLogs, !disableFileLogs ); + Log::create( mLogsPath, logLevel, stdOutLogs, !disableFileLogs ); #else - Log::create( mConfigPath + "ecode.log", logLevel, stdOutLogs, !disableFileLogs ); + Log::create( mLogsPath, logLevel, stdOutLogs, !disableFileLogs ); #endif Log::instance()->setKeepLog( true ); @@ -3480,7 +3482,7 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN mFileWatcher = new efsw::FileWatcher(); - mFileSystemListener = new FileSystemListener( mSplitter, mFileSystemModel ); + mFileSystemListener = new FileSystemListener( mSplitter, mFileSystemModel, { mLogsPath } ); mFileWatcher->addWatch( mPluginsPath, mFileSystemListener ); mFileWatcher->watch(); mPluginManager->setFileSystemListener( mFileSystemListener ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index f0af10610..ea487c886 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -457,6 +457,7 @@ class App : public UICodeEditorSplitter::Client { std::string mResPath; std::string mLanguagesPath; std::string mThemesPath; + std::string mLogsPath; Float mDisplayDPI{ 96 }; std::shared_ptr mThreadPool; std::shared_ptr mDirTree; diff --git a/src/tools/ecode/filesystemlistener.cpp b/src/tools/ecode/filesystemlistener.cpp index 139342a69..40167bf52 100644 --- a/src/tools/ecode/filesystemlistener.cpp +++ b/src/tools/ecode/filesystemlistener.cpp @@ -19,8 +19,9 @@ std::string getFileSystemEventTypeName( FileSystemEventType action ) { } FileSystemListener::FileSystemListener( UICodeEditorSplitter* splitter, - std::shared_ptr fileSystemModel ) : - mSplitter( splitter ), mFileSystemModel( fileSystemModel ) {} + std::shared_ptr fileSystemModel, + const std::vector& ignoreFiles ) : + mSplitter( splitter ), mFileSystemModel( fileSystemModel ), mIgnoredFiles( ignoreFiles ) {} static inline bool endsWithSlash( const std::string& dir ) { return !dir.empty() && ( dir.back() == '\\' || dir.back() == '/' ); @@ -138,7 +139,8 @@ bool FileSystemListener::isFileOpen( const FileInfo& file ) { void FileSystemListener::notifyChange( const FileInfo& file ) { mSplitter->forEachDoc( [&]( TextDocument& doc ) { - if ( file.getFilepath() == doc.getFileInfo().getFilepath() && + if ( !isIgnored( file.getFilepath() ) && + file.getFilepath() == doc.getFileInfo().getFilepath() && file.getModificationTime() != doc.getFileInfo().getModificationTime() && !doc.isSaving() ) { MD5::Digest curHash = MD5::fromFile( file.getFilepath() ).digest; @@ -163,4 +165,8 @@ void FileSystemListener::notifyMove( const FileInfo& oldFile, const FileInfo& ne } ); } +bool FileSystemListener::isIgnored( const std::string& path ) { + return std::find( mIgnoredFiles.begin(), mIgnoredFiles.end(), path ) != mIgnoredFiles.end(); +} + } // namespace ecode diff --git a/src/tools/ecode/filesystemlistener.hpp b/src/tools/ecode/filesystemlistener.hpp index 5474e69d2..b9786c28a 100644 --- a/src/tools/ecode/filesystemlistener.hpp +++ b/src/tools/ecode/filesystemlistener.hpp @@ -22,7 +22,8 @@ class FileSystemListener : public efsw::FileWatchListener { typedef std::function FileEventFn; FileSystemListener( UICodeEditorSplitter* codeSplitter, - std::shared_ptr fileSystemModel ); + std::shared_ptr fileSystemModel, + const std::vector& ignoreFiles ); virtual ~FileSystemListener() {} @@ -43,6 +44,7 @@ class FileSystemListener : public efsw::FileWatchListener { std::shared_ptr mDirTree; std::atomic mLastId{ 0 }; std::unordered_map mCbs; + std::vector mIgnoredFiles; Mutex mCbsMutex; bool isFileOpen( const FileInfo& file ); @@ -50,6 +52,8 @@ class FileSystemListener : public efsw::FileWatchListener { void notifyChange( const FileInfo& file ); void notifyMove( const FileInfo& oldFile, const FileInfo& newFile ); + + bool isIgnored( const std::string& path ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.cpp b/src/tools/ecode/plugins/formatter/formatterplugin.cpp index 90902a905..615e0b826 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.cpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #define PUGIXML_HEADER_ONLY #include