mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 18:50:16 +03:00
perf: reduce allocations across UI and editor hot paths
- reuse formatting, document text, property resolution, and layout storage - use inline containers for interpolations, callbacks, wrapping, and matcher state - optimize single-line insertion by mutating document lines without splitting - iterate PATH entries directly in Sys::which and reuse candidate buffers - avoid temporary clocks and string copies in frequent ecode plugin updates - retain documents during autocomplete cache jobs and prevent duplicate scheduling - fix PatternMatcher copy assignment and MSVC move-only container compilation - expand coverage for matching, text insertion, reusable strings, and Sys::which
This commit is contained in:
@@ -1568,14 +1568,15 @@ void App::updateDocInfo( TextDocument& doc ) {
|
||||
mDocInfo && mSplitter->curEditorExistsAndFocused() ) {
|
||||
mDocInfo->setVisible( true );
|
||||
updateDocInfoLocation();
|
||||
String infoStr( String::format(
|
||||
"%s: %lld / %zu %s: %lld %s %s%s %s", i18n( "line_abbr", "line" ).toUtf8(),
|
||||
doc.getSelection().start().line() + 1, doc.linesCount(),
|
||||
i18n( "col_abbr", "col" ).toUtf8(), mSplitter->getCurEditor()->getCurrentColumnCount(),
|
||||
doc.getSyntaxDefinition().getLanguageName(),
|
||||
TextFormat::encodingToString( doc.getEncoding() ), doc.isBOM() ? " (with BOM)"sv : ""sv,
|
||||
TextFormat::lineEndingToString( doc.getLineEnding() ) ) );
|
||||
mDocInfo->debounce( [this, infoStr] { mDocInfo->setText( infoStr ); }, Time::Zero,
|
||||
String::formatTo( mDocInfoUtf8Buffer, "%s: %lld / %zu %s: %lld %s %s%s %s",
|
||||
mDocInfoLineAbbr, doc.getSelection().start().line() + 1, doc.linesCount(),
|
||||
mDocInfoColAbbr, mSplitter->getCurEditor()->getCurrentColumnCount(),
|
||||
doc.getSyntaxDefinition().getLanguageName(),
|
||||
TextFormat::encodingToString( doc.getEncoding() ),
|
||||
doc.isBOM() ? " (with BOM)"sv : ""sv,
|
||||
TextFormat::lineEndingToString( doc.getLineEnding() ) );
|
||||
mDocInfoText.assignUtf8( mDocInfoUtf8Buffer );
|
||||
mDocInfo->debounce( [this] { mDocInfo->setText( mDocInfoText ); }, Time::Zero,
|
||||
String::hash( "ecode::doc_info::update" ) );
|
||||
}
|
||||
}
|
||||
@@ -4872,6 +4873,8 @@ void App::init( InitParameters& params ) {
|
||||
mUISceneNode->bind( "code_container", mBaseLayout );
|
||||
mUISceneNode->bind( "image_container", mImageLayout );
|
||||
mUISceneNode->bind( "doc_info", mDocInfo );
|
||||
mDocInfoLineAbbr = i18n( "line_abbr", "line" ).toUtf8();
|
||||
mDocInfoColAbbr = i18n( "col_abbr", "col" ).toUtf8();
|
||||
mUISceneNode->bind( "panel", mSidePanel );
|
||||
mUISceneNode->bind( "project_splitter", mProjectSplitter );
|
||||
mUISceneNode->bind( "main_menubar", mMenuBar );
|
||||
|
||||
@@ -668,6 +668,10 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
|
||||
UILayout* mBaseLayout{ nullptr };
|
||||
UILayout* mImageLayout{ nullptr };
|
||||
UITextView* mDocInfo{ nullptr };
|
||||
std::string mDocInfoLineAbbr;
|
||||
std::string mDocInfoColAbbr;
|
||||
std::string mDocInfoUtf8Buffer;
|
||||
String mDocInfoText;
|
||||
std::vector<std::string> mRecentFiles;
|
||||
std::stack<std::string> mRecentClosedFiles;
|
||||
std::unordered_map<std::string, TextRanges> mClosedDocumentState;
|
||||
|
||||
@@ -1041,22 +1041,19 @@ bool AutoCompletePlugin::onTextInput( UICodeEditor* editor, const TextInputEvent
|
||||
return false;
|
||||
}
|
||||
|
||||
void AutoCompletePlugin::updateDocCache( TextDocument* doc ) {
|
||||
ScopedOp op(
|
||||
[this, doc] {
|
||||
Lock lu( mDocsUpdatingMutex );
|
||||
mDocsUpdating[doc] = true;
|
||||
},
|
||||
[this, doc] {
|
||||
Lock lu( mDocsUpdatingMutex );
|
||||
mDocsUpdating[doc] = false;
|
||||
} );
|
||||
void AutoCompletePlugin::updateDocCache( std::shared_ptr<TextDocument> doc ) {
|
||||
TextDocument* docPtr = doc.get();
|
||||
ScopedOp op( [] {},
|
||||
[this, docPtr] {
|
||||
Lock lu( mDocsUpdatingMutex );
|
||||
mDocsUpdating[docPtr] = false;
|
||||
} );
|
||||
|
||||
Clock clock;
|
||||
std::unordered_map<TextDocument*, DocCache>::iterator docCache;
|
||||
{
|
||||
Lock l( mDocMutex );
|
||||
docCache = mDocCache.find( doc );
|
||||
docCache = mDocCache.find( docPtr );
|
||||
if ( docCache == mDocCache.end() || mShuttingDown )
|
||||
return;
|
||||
}
|
||||
@@ -1066,7 +1063,7 @@ void AutoCompletePlugin::updateDocCache( TextDocument* doc ) {
|
||||
|
||||
{
|
||||
Lock l( mDocMutex );
|
||||
docCache = mDocCache.find( doc );
|
||||
docCache = mDocCache.find( docPtr );
|
||||
if ( docCache == mDocCache.end() || mShuttingDown )
|
||||
return;
|
||||
auto& cache = docCache->second;
|
||||
@@ -1966,14 +1963,20 @@ void AutoCompletePlugin::update( UICodeEditor* editor ) {
|
||||
Lock l( mDocMutex );
|
||||
for ( auto& doc : mDocs ) {
|
||||
if ( !doc->isLoading() && mDocCache[doc].changeId != doc->getCurrentChangeId() ) {
|
||||
auto docRef = getPluginContext()->getSplitter()->getTextDocumentRef( doc );
|
||||
if ( !docRef )
|
||||
continue;
|
||||
{
|
||||
Lock lu( mDocsUpdatingMutex );
|
||||
auto du = mDocsUpdating.find( doc );
|
||||
// Dont update the document cache if it's still updating the document
|
||||
if ( du != mDocsUpdating.end() && du->second == true )
|
||||
auto& updating = mDocsUpdating[doc];
|
||||
// Don't queue another cache update while one is queued or running.
|
||||
if ( updating )
|
||||
continue;
|
||||
updating = true;
|
||||
}
|
||||
mThreadPool->run( [this, doc] { updateDocCache( doc ); } );
|
||||
mThreadPool->run( [this, doc = std::move( docRef )]() mutable {
|
||||
updateDocCache( std::move( doc ) );
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2484,13 +2487,13 @@ void AutoCompletePlugin::resetSignatureHelp() {
|
||||
mSignatureHelpEditor = nullptr;
|
||||
}
|
||||
|
||||
AutoCompletePlugin::SymbolsList AutoCompletePlugin::getDocumentSymbols( TextDocument* doc ) {
|
||||
AutoCompletePlugin::SymbolsList
|
||||
AutoCompletePlugin::getDocumentSymbols( const std::shared_ptr<TextDocument>& docRef ) {
|
||||
static constexpr auto MAX_LINE_COUNT = EE_1KB * 10;
|
||||
AutoCompletePlugin::SymbolsList symbols;
|
||||
std::shared_ptr<TextDocument> docRef =
|
||||
getPluginContext()->getSplitter()->getTextDocumentRef( doc ); // acquire a doc
|
||||
if ( docRef == nullptr )
|
||||
if ( !docRef )
|
||||
return symbols;
|
||||
TextDocument* doc = docRef.get();
|
||||
LuaPattern pattern( mSymbolPattern );
|
||||
if ( doc->linesCount() == 0 || doc->isHuge() || mShuttingDown )
|
||||
return symbols;
|
||||
|
||||
@@ -266,9 +266,9 @@ class AutoCompletePlugin : public Plugin {
|
||||
|
||||
void updateSuggestions( const std::string& symbol, UICodeEditor* editor );
|
||||
|
||||
SymbolsList getDocumentSymbols( TextDocument* );
|
||||
SymbolsList getDocumentSymbols( const std::shared_ptr<TextDocument>& doc );
|
||||
|
||||
void updateDocCache( TextDocument* doc );
|
||||
void updateDocCache( std::shared_ptr<TextDocument> doc );
|
||||
|
||||
std::string getPartialSymbol( TextDocument* doc );
|
||||
|
||||
|
||||
@@ -746,9 +746,9 @@ void LinterPlugin::onUnregister( UICodeEditor* editor ) {
|
||||
void LinterPlugin::update( UICodeEditor* editor ) {
|
||||
std::shared_ptr<TextDocument> doc = editor->getDocumentRef();
|
||||
auto it = mDirtyDoc.find( doc.get() );
|
||||
if ( it != mDirtyDoc.end() && it->second->getElapsedTime() >= mDelayTime ) {
|
||||
if ( it != mDirtyDoc.end() && it->second.getElapsedTime() >= mDelayTime ) {
|
||||
mDirtyDoc.erase( doc.get() );
|
||||
mThreadPool->run( [this, doc] { lintDoc( doc ); } );
|
||||
mThreadPool->run( [this, doc = std::move( doc )] { lintDoc( doc ); } );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1469,10 +1469,12 @@ Linter LinterPlugin::supportsLinter( std::shared_ptr<TextDocument> doc ) {
|
||||
}
|
||||
|
||||
void LinterPlugin::setDocDirty( TextDocument* doc ) {
|
||||
mDirtyDoc[doc] = std::make_unique<Clock>();
|
||||
auto [it, inserted] = mDirtyDoc.try_emplace( doc );
|
||||
if ( !inserted )
|
||||
it->second.restart();
|
||||
}
|
||||
void LinterPlugin::setDocDirty( UICodeEditor* editor ) {
|
||||
mDirtyDoc[editor->getDocumentRef().get()] = std::make_unique<Clock>();
|
||||
setDocDirty( editor->getDocumentRef().get() );
|
||||
}
|
||||
|
||||
void LinterPlugin::invalidateEditors( TextDocument* doc ) {
|
||||
|
||||
@@ -131,7 +131,7 @@ class LinterPlugin : public Plugin {
|
||||
std::unordered_map<UICodeEditor*, std::vector<Uint32>> mEditors;
|
||||
std::unordered_set<TextDocument*> mDocs;
|
||||
std::unordered_map<UICodeEditor*, TextDocument*> mEditorDocs;
|
||||
std::unordered_map<TextDocument*, std::unique_ptr<Clock>> mDirtyDoc;
|
||||
std::unordered_map<TextDocument*, Clock> mDirtyDoc;
|
||||
std::unordered_map<TextDocument*, std::map<Int64, std::vector<LinterMatch>>> mMatches;
|
||||
Time mDelayTime{ Seconds( 0.5f ) };
|
||||
Mutex mDocMutex;
|
||||
|
||||
@@ -230,19 +230,21 @@ void SpellCheckerPlugin::onRegisterListeners( UICodeEditor* editor,
|
||||
}
|
||||
|
||||
void SpellCheckerPlugin::setDocDirty( TextDocument* doc ) {
|
||||
mDirtyDoc[doc] = std::make_unique<Clock>();
|
||||
auto [it, inserted] = mDirtyDoc.try_emplace( doc );
|
||||
if ( !inserted )
|
||||
it->second.restart();
|
||||
}
|
||||
|
||||
void SpellCheckerPlugin::setDocDirty( UICodeEditor* editor ) {
|
||||
mDirtyDoc[editor->getDocumentRef().get()] = std::make_unique<Clock>();
|
||||
setDocDirty( editor->getDocumentRef().get() );
|
||||
}
|
||||
|
||||
void SpellCheckerPlugin::update( UICodeEditor* editor ) {
|
||||
std::shared_ptr<TextDocument> doc = editor->getDocumentRef();
|
||||
auto it = mDirtyDoc.find( doc.get() );
|
||||
if ( it != mDirtyDoc.end() && it->second->getElapsedTime() >= mDelayTime ) {
|
||||
if ( it != mDirtyDoc.end() && it->second.getElapsedTime() >= mDelayTime ) {
|
||||
mDirtyDoc.erase( doc.get() );
|
||||
mThreadPool->run( [this, doc] { spellCheckDoc( doc ); } );
|
||||
mThreadPool->run( [this, doc = std::move( doc )] { spellCheckDoc( doc ); } );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,11 +256,11 @@ void SpellCheckerPlugin::spellCheckDoc( std::shared_ptr<TextDocument> doc ) {
|
||||
return;
|
||||
|
||||
ScopedOp op(
|
||||
[this, doc]() {
|
||||
[this] {
|
||||
std::lock_guard l( mWorkMutex );
|
||||
mWorkersCount++;
|
||||
},
|
||||
[this]() {
|
||||
[this] {
|
||||
{
|
||||
std::lock_guard l( mWorkMutex );
|
||||
mWorkersCount--;
|
||||
|
||||
@@ -57,7 +57,7 @@ class SpellCheckerPlugin : public PluginBase {
|
||||
|
||||
protected:
|
||||
Time mDelayTime{ Seconds( 0.5f ) };
|
||||
std::unordered_map<TextDocument*, std::unique_ptr<Clock>> mDirtyDoc;
|
||||
std::unordered_map<TextDocument*, Clock> mDirtyDoc;
|
||||
std::unordered_map<TextDocument*, std::map<Int64, std::vector<SpellCheckerMatch>>> mMatches;
|
||||
std::set<std::string> mLanguagesDisabled;
|
||||
std::set<std::string> mLSPLanguagesDisabled;
|
||||
|
||||
@@ -253,7 +253,7 @@ void XMLToolsPlugin::XMLToolsClient::updateMatch( const TextRange& sel ) {
|
||||
const auto& line = mDoc->line( mDoc->getSelection().start().line() ).getText();
|
||||
if ( mDoc->getSelection().start().column() >= (Int64)line.size() )
|
||||
return clearMatch();
|
||||
auto def = mDoc->getHighlighter()->getSyntaxDefinitionFromTextPosition( sel.start() );
|
||||
const auto& def = mDoc->getHighlighter()->getSyntaxDefinitionFromTextPosition( sel.start() );
|
||||
if ( !def.getAutoCloseXMLTags() ) // getAutoCloseXMLTags means that it supports XML element tags
|
||||
return clearMatch();
|
||||
TextRange range = mDoc->getWordRangeInPosition( sel.start(), false );
|
||||
|
||||
Reference in New Issue
Block a user