diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp
index f2dbb4e8c..e783ea4c7 100644
--- a/src/tools/codeeditor/codeeditor.cpp
+++ b/src/tools/codeeditor/codeeditor.cpp
@@ -2310,6 +2310,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
+
diff --git a/src/tools/codeeditor/globalsearchcontroller.cpp b/src/tools/codeeditor/globalsearchcontroller.cpp
index 80bb844e7..15bd24bb3 100644
--- a/src/tools/codeeditor/globalsearchcontroller.cpp
+++ b/src/tools/codeeditor/globalsearchcontroller.cpp
@@ -8,58 +8,39 @@ GlobalSearchController::GlobalSearchController( UICodeEditorSplitter* editorSpli
UISceneNode* sceneNode, App* app ) :
mEditorSplitter( editorSplitter ), mUISceneNode( sceneNode ), mApp( app ) {}
-static String replaceInText( String text, const String& replaceText,
- std::vector replacements ) {
+static bool replaceInFile( const std::string& path, const std::string& replaceText,
+ const std::vector>& replacements ) {
+ std::string data;
+ if ( !FileSystem::fileGet( path, data ) )
+ return false;
+
Int64 diff = 0;
- String oldText( text );
+
for ( const auto& range : replacements ) {
- Int64 len = range.end().column() - range.start().column();
- auto before = text.substr( 0, range.start().column() + diff );
- auto after = !text.empty() ? text.substr( range.end().column() + diff ) : "";
- text = before + replaceText + after;
- diff += replaceText.size() - len;
+ data.replace( range.first + diff, range.second - range.first, replaceText );
+ diff += replaceText.size() - ( range.second - range.first );
}
- return text;
+
+ if ( !FileSystem::fileWrite( path, (const Uint8*)data.c_str(), data.size() ) )
+ return false;
+
+ return true;
}
-size_t GlobalSearchController::replaceInFiles( const String& replaceText,
+size_t GlobalSearchController::replaceInFiles( const std::string& replaceText,
std::shared_ptr model ) {
const ProjectSearch::Result& res = model.get()->getResult();
size_t count = 0;
for ( const auto& fileResult : res ) {
- std::map>> replaceRangeMap;
- std::map replaceStringMap;
- for ( const auto& result : fileResult.results ) {
- if ( result.selected ) {
- replaceRangeMap[result.position.start().line()].first = result.line;
- replaceRangeMap[result.position.start().line()].second.push_back( result.position );
- count++;
- }
- }
+ std::vector> replacements;
- for ( const auto& replace : replaceRangeMap )
- replaceStringMap[replace.second.second.front().start().line()] =
- replaceInText( replace.second.first, replaceText, replace.second.second );
+ for ( const auto& result : fileResult.results )
+ if ( result.selected )
+ replacements.push_back( { result.start, result.end } );
- std::shared_ptr doc = mEditorSplitter->findDocFromPath( fileResult.file );
- bool loaded = doc ? true : false;
- bool save = false;
- bool inMemoryAndNotDirty = doc ? !doc->isDirty() : false;
-
- if ( !doc ) {
- doc = std::make_shared();
- loaded = doc->loadFromFile( fileResult.file );
- save = true;
- }
-
- if ( doc && loaded ) {
- for ( const auto& replaceString : replaceStringMap )
- doc->replaceLine( replaceString.first, replaceString.second );
-
- if ( save || inMemoryAndNotDirty )
- doc->save();
- }
+ if ( replaceInFile( fileResult.file, replaceText, replacements ) )
+ count += replacements.size();
}
return count;
@@ -82,28 +63,33 @@ void GlobalSearchController::initGlobalSearchBar( UIGlobalSearchBar* globalSearc
UICheckBox* wholeWordChk = mGlobalSearchBarLayout->find( "whole_word" );
UICheckBox* luaPatternChk = mGlobalSearchBarLayout->find( "lua_pattern" );
UIWidget* searchBarClose = mGlobalSearchBarLayout->find( "global_searchbar_close" );
+ UICheckBox* escapeSequenceChk = mGlobalSearchBarLayout->find( "escape_sequence" );
mGlobalSearchInput = mGlobalSearchBarLayout->find( "global_search_find" );
+
mGlobalSearchHistoryList =
mGlobalSearchBarLayout->find( "global_search_history" );
mGlobalSearchBarLayout->addCommand(
- "search-in-files", [&, caseSensitiveChk, wholeWordChk, luaPatternChk] {
+ "search-in-files", [&, caseSensitiveChk, wholeWordChk, luaPatternChk, escapeSequenceChk] {
doGlobalSearch( mGlobalSearchInput->getText(), caseSensitiveChk->isChecked(),
- wholeWordChk->isChecked(), luaPatternChk->isChecked(), false );
+ wholeWordChk->isChecked(), luaPatternChk->isChecked(),
+ escapeSequenceChk->isChecked(), false );
} );
mGlobalSearchBarLayout->addCommand(
- "search-replace-in-files", [&, caseSensitiveChk, wholeWordChk, luaPatternChk] {
+ "search-replace-in-files",
+ [&, caseSensitiveChk, wholeWordChk, luaPatternChk, escapeSequenceChk] {
doGlobalSearch( mGlobalSearchInput->getText(), caseSensitiveChk->isChecked(),
- wholeWordChk->isChecked(), luaPatternChk->isChecked(), true );
+ wholeWordChk->isChecked(), luaPatternChk->isChecked(),
+ escapeSequenceChk->isChecked(), true );
} );
mGlobalSearchBarLayout->addCommand(
- "search-again", [&, caseSensitiveChk, wholeWordChk, luaPatternChk] {
+ "search-again", [&, caseSensitiveChk, wholeWordChk, luaPatternChk, escapeSequenceChk] {
auto listBox = mGlobalSearchHistoryList->getListBox();
if ( listBox->getItemSelectedIndex() < mGlobalSearchHistory.size() ) {
doGlobalSearch( mGlobalSearchHistory[mGlobalSearchHistory.size() - 1 -
listBox->getItemSelectedIndex()]
.first,
caseSensitiveChk->isChecked(), wholeWordChk->isChecked(),
- luaPatternChk->isChecked(),
+ luaPatternChk->isChecked(), escapeSequenceChk->isChecked(),
mGlobalSearchTreeReplace == mGlobalSearchTree, true );
}
} );
@@ -127,8 +113,9 @@ void GlobalSearchController::initGlobalSearchBar( UIGlobalSearchBar* globalSearc
{ "ctrl+l", "toggle-lua-pattern" },
{ "ctrl+r", "search-replace-in-files" },
{ "ctrl+g", "search-again" },
- { "ctrl+e", "expand-all" },
+ { "ctrl+a", "expand-all" },
{ "ctrl+shift+e", "collapse-all" },
+ { "ctrl+e", "change-escape-sequence" },
} );
mGlobalSearchBarLayout->addCommand( "change-case", [&, caseSensitiveChk] {
caseSensitiveChk->setChecked( !caseSensitiveChk->isChecked() );
@@ -139,6 +126,9 @@ void GlobalSearchController::initGlobalSearchBar( UIGlobalSearchBar* globalSearc
mGlobalSearchBarLayout->addCommand( "toggle-lua-pattern", [&, luaPatternChk] {
luaPatternChk->setChecked( !luaPatternChk->isChecked() );
} );
+ mGlobalSearchBarLayout->addCommand( "change-escape-sequence", [&, escapeSequenceChk] {
+ escapeSequenceChk->setChecked( !escapeSequenceChk->isChecked() );
+ } );
mGlobalSearchInput->addEventListener( Event::OnPressEnter, [&]( const Event* ) {
if ( mGlobalSearchInput->hasFocus() ) {
mGlobalSearchBarLayout->execute( "search-in-files" );
@@ -206,12 +196,15 @@ void GlobalSearchController::initGlobalSearchBar( UIGlobalSearchBar* globalSearc
if ( keyEvent->getKeyCode() == KEY_ESCAPE )
mGlobalSearchBarLayout->execute( "close-global-searchbar" );
} );
- mGlobalSearchBarLayout->addCommand( "replace-in-files", [&, replaceInput] {
+ mGlobalSearchBarLayout->addCommand( "replace-in-files", [&, replaceInput, escapeSequenceChk] {
auto listBox = mGlobalSearchHistoryList->getListBox();
if ( listBox->getItemSelectedIndex() < mGlobalSearchHistory.size() ) {
const auto& replaceData = mGlobalSearchHistory[mGlobalSearchHistory.size() - 1 -
listBox->getItemSelectedIndex()];
- size_t count = replaceInFiles( replaceInput->getText(), replaceData.second );
+ String text( replaceInput->getText() );
+ if ( escapeSequenceChk->isChecked() )
+ text.unescape();
+ size_t count = replaceInFiles( text.toUtf8(), replaceData.second );
mGlobalSearchBarLayout->execute( "search-again" );
mGlobalSearchBarLayout->execute( "close-global-searchbar" );
mApp->getNotificationCenter()->addNotification(
@@ -237,10 +230,17 @@ void GlobalSearchController::showGlobalSearch( bool searchReplace ) {
mGlobalSearchBarLayout->setVisible( true )->setEnabled( true );
mGlobalSearchInput->setFocus();
mGlobalSearchLayout->setVisible( true );
+ UICheckBox* escapeSequenceChk = mGlobalSearchBarLayout->find( "escape_sequence" );
if ( mEditorSplitter->getCurEditor() &&
mEditorSplitter->getCurEditor()->getDocument().hasSelection() ) {
- mGlobalSearchInput->setText(
- mEditorSplitter->getCurEditor()->getDocument().getSelectedText() );
+ auto& doc = mEditorSplitter->getCurEditor()->getDocument();
+ String text = doc.getSelectedText();
+ if ( !doc.getSelection().inSameLine() ) {
+ text.escape();
+ if ( !escapeSequenceChk->isChecked() )
+ escapeSequenceChk->setChecked( true );
+ }
+ mGlobalSearchInput->setText( text );
}
mGlobalSearchInput->getDocument().selectAll();
auto* loader = mGlobalSearchTree->getParent()->find( "loader" );
@@ -252,7 +252,7 @@ void GlobalSearchController::showGlobalSearch( bool searchReplace ) {
updateGlobalSearchBarResults( mGlobalSearchTreeReplace->getSearchStr(),
std::static_pointer_cast(
mGlobalSearchTreeReplace->getModelShared() ),
- searchReplace );
+ searchReplace, escapeSequenceChk->isChecked() );
}
}
updateGlobalSearchBar();
@@ -293,7 +293,7 @@ void GlobalSearchController::hideGlobalSearchBar() {
void GlobalSearchController::updateGlobalSearchBarResults(
const std::string& search, std::shared_ptr model,
- bool searchReplace ) {
+ bool searchReplace, bool isEscaped ) {
updateGlobalSearchBar();
mGlobalSearchTree->setSearchStr( search );
mGlobalSearchTree->setModel( model );
@@ -307,14 +307,15 @@ void GlobalSearchController::updateGlobalSearchBarResults(
if ( searchReplace && mGlobalSearchBarLayout->isVisible() ) {
auto* replaceInput =
mGlobalSearchLayout->find( "global_search_replace_input" );
- replaceInput->setText( search );
+ replaceInput->setText( isEscaped ? String( search ).escape().toUtf8() : search );
+ replaceInput->getDocument().selectAll();
replaceInput->setFocus();
}
}
-void GlobalSearchController::doGlobalSearch( const String& text, bool caseSensitive, bool wholeWord,
- bool luaPattern, bool searchReplace,
- bool searchAgain ) {
+void GlobalSearchController::doGlobalSearch( String text, bool caseSensitive, bool wholeWord,
+ bool luaPattern, bool escapeSequence,
+ bool searchReplace, bool searchAgain ) {
if ( mApp->getDirTree() && mApp->getDirTree()->getFilesCount() > 0 && !text.empty() ) {
mGlobalSearchTree = searchReplace ? mGlobalSearchTreeReplace : mGlobalSearchTreeSearch;
mGlobalSearchTreeSearch->setVisible( !searchReplace );
@@ -326,11 +327,12 @@ void GlobalSearchController::doGlobalSearch( const String& text, bool caseSensit
loader->setId( "loader" );
loader->setRadius( 48 );
loader->setOutlineThickness( 6 );
- loader->setFillColor( Color::Red );
loader->setParent( mGlobalSearchLayout->getParent() );
loader->setPosition( mGlobalSearchLayout->getPosition() +
mGlobalSearchLayout->getSize() * 0.5f - loader->getSize() * 0.5f );
Clock* clock = eeNew( Clock, () );
+ if ( escapeSequence )
+ text.unescape();
std::string search( text.toUtf8() );
ProjectSearch::find(
mApp->getDirTree()->getFiles(), search,
@@ -342,8 +344,8 @@ void GlobalSearchController::doGlobalSearch( const String& text, bool caseSensit
Log::info( "Global search for \"%s\" took %.2fms", search.c_str(),
clock->getElapsedTime().asMilliseconds() );
eeDelete( clock );
- mUISceneNode->runOnMainThread( [&, loader, res, search, searchReplace,
- searchAgain] {
+ mUISceneNode->runOnMainThread( [&, loader, res, search, searchReplace, searchAgain,
+ escapeSequence] {
auto model = ProjectSearch::asModel( res );
auto listBox = mGlobalSearchHistoryList->getListBox();
@@ -372,7 +374,7 @@ void GlobalSearchController::doGlobalSearch( const String& text, bool caseSensit
auto idxItem = mGlobalSearchHistory.at(
mGlobalSearchHistory.size() - 1 - idx );
updateGlobalSearchBarResults( idxItem.first, idxItem.second,
- searchReplace );
+ searchReplace, escapeSequence );
} );
} else if ( listBox->getItemSelectedIndex() < mGlobalSearchHistory.size() ) {
mGlobalSearchHistory[mGlobalSearchHistory.size() - 1 -
@@ -380,7 +382,7 @@ void GlobalSearchController::doGlobalSearch( const String& text, bool caseSensit
.second = model;
}
- updateGlobalSearchBarResults( search, model, searchReplace );
+ updateGlobalSearchBarResults( search, model, searchReplace, escapeSequence );
loader->setVisible( false );
loader->close();
} );
diff --git a/src/tools/codeeditor/globalsearchcontroller.hpp b/src/tools/codeeditor/globalsearchcontroller.hpp
index 5a8e0f98b..378a3c10e 100644
--- a/src/tools/codeeditor/globalsearchcontroller.hpp
+++ b/src/tools/codeeditor/globalsearchcontroller.hpp
@@ -20,14 +20,14 @@ class GlobalSearchController {
void updateGlobalSearchBarResults( const std::string& search,
std::shared_ptr model,
- bool searchReplace );
+ bool searchReplace, bool isEscaped );
void initGlobalSearchTree( UITreeViewGlobalSearch* searchTree );
- void doGlobalSearch( const String& text, bool caseSensitive, bool wholeWord, bool luaPattern,
- bool searchReplace, bool searchAgain = false );
+ void doGlobalSearch( String text, bool caseSensitive, bool wholeWord, bool luaPattern,
+ bool escapeSequence, bool searchReplace, bool searchAgain = false );
- size_t replaceInFiles( const String& replaceText,
+ size_t replaceInFiles( const std::string& replaceText,
std::shared_ptr model );
void showGlobalSearch( bool searchAndReplace = false );
diff --git a/src/tools/codeeditor/projectsearch.cpp b/src/tools/codeeditor/projectsearch.cpp
index 3b742ee8f..8185652fd 100644
--- a/src/tools/codeeditor/projectsearch.cpp
+++ b/src/tools/codeeditor/projectsearch.cpp
@@ -46,47 +46,35 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo
Int64 searchRes = 0;
size_t totNl = 0;
FileSystem::fileGet( file, fileText );
+ std::string fileTextOriginal;
+
if ( !caseSensitive ) {
- std::string fileTextOriginal( fileText );
+ fileTextOriginal = fileText;
String::toLowerInPlace( fileText );
- do {
- searchRes = String::BMH::find( fileText, text, searchRes, occ );
- if ( searchRes != -1 ) {
- if ( wholeWord && !String::isWholeWord( fileText, text, searchRes ) ) {
- lSearchRes = searchRes;
- searchRes += text.size();
- continue;
- }
- size_t relCol;
- totNl += countNewLines( fileText, lSearchRes, searchRes );
- String str( textLine( fileTextOriginal, searchRes, relCol ) );
- res.push_back( { str,
- { { (Int64)totNl, (Int64)relCol },
- { (Int64)totNl, (Int64)( relCol + text.size() ) } } } );
- lSearchRes = searchRes;
- searchRes += text.size();
- }
- } while ( searchRes != -1 );
- } else {
- do {
- searchRes = String::BMH::find( fileText, text, searchRes, occ );
- if ( searchRes != -1 ) {
- if ( wholeWord && !String::isWholeWord( fileText, text, searchRes ) ) {
- lSearchRes = searchRes;
- searchRes += text.size();
- continue;
- }
- size_t relCol;
- totNl += countNewLines( fileText, lSearchRes, searchRes );
- String str( textLine( fileText, searchRes, relCol ) );
- res.push_back( { str,
- { { (Int64)totNl, (Int64)relCol },
- { (Int64)totNl, (Int64)( relCol + text.size() ) } } } );
- lSearchRes = searchRes;
- searchRes += text.size();
- }
- } while ( searchRes != -1 );
}
+
+ do {
+ searchRes = String::BMH::find( fileText, text, searchRes, occ );
+ if ( searchRes != -1 ) {
+ if ( wholeWord && !String::isWholeWord( fileText, text, searchRes ) ) {
+ lSearchRes = searchRes;
+ searchRes += text.size();
+ continue;
+ }
+ size_t relCol;
+ totNl += countNewLines( fileText, lSearchRes, searchRes );
+ String str(
+ textLine( caseSensitive ? fileText : fileTextOriginal, searchRes, relCol ) );
+ res.push_back( { str,
+ { { (Int64)totNl, (Int64)relCol },
+ { (Int64)totNl, (Int64)( relCol + text.size() ) } },
+ searchRes,
+ static_cast( searchRes + text.size() ) } );
+ lSearchRes = searchRes;
+ searchRes += text.size();
+ }
+ } while ( searchRes != -1 );
+
return res;
}
@@ -100,47 +88,34 @@ searchInFileLuaPattern( const std::string& file, const std::string& text, const
size_t totNl = 0;
bool matched = false;
Int64 searchRes = 0;
+ std::string fileTextOriginal;
+
if ( !caseSensitive ) {
- std::string fileTextOriginal( fileText );
+ fileTextOriginal = fileText;
String::toLowerInPlace( fileText );
- do {
- int start, end = 0;
- if ( ( matched = pattern.find( fileText, start, end, searchRes ) ) ) {
- if ( wholeWord && !String::isWholeWord(
- fileText, fileText.substr( start, end - start ), start ) ) {
- searchRes = end;
- continue;
- }
- size_t relCol;
- totNl += countNewLines( fileText, searchRes, end );
- String str( textLine( fileTextOriginal, start, relCol ) );
- int len = end - start;
- res.push_back( { str,
- { { (Int64)totNl, (Int64)relCol },
- { (Int64)totNl, (Int64)( relCol + len ) } } } );
- searchRes = end;
- }
- } while ( matched );
- } else {
- do {
- int start, end = 0;
- if ( ( matched = pattern.find( fileText, start, end, searchRes ) ) ) {
- if ( wholeWord && !String::isWholeWord(
- fileText, fileText.substr( start, end - start ), start ) ) {
- searchRes = end;
- continue;
- }
- size_t relCol;
- totNl += countNewLines( fileText, searchRes, end );
- String str( textLine( fileText, start, relCol ) );
- int len = end - start;
- res.push_back( { str,
- { { (Int64)totNl, (Int64)relCol },
- { (Int64)totNl, (Int64)( relCol + len ) } } } );
- searchRes = end;
- }
- } while ( matched );
}
+
+ do {
+ int start, end = 0;
+ if ( ( matched = pattern.find( fileText, start, end, searchRes ) ) ) {
+ if ( wholeWord &&
+ !String::isWholeWord( fileText, fileText.substr( start, end - start ), start ) ) {
+ searchRes = end;
+ continue;
+ }
+ size_t relCol;
+ totNl += countNewLines( fileText, searchRes, end );
+ String str( textLine( caseSensitive ? fileText : fileTextOriginal, start, relCol ) );
+ int len = end - start;
+ res.push_back(
+ { str,
+ { { (Int64)totNl, (Int64)relCol }, { (Int64)totNl, (Int64)( relCol + len ) } },
+ start,
+ end } );
+ searchRes = end;
+ }
+ } while ( matched );
+
return res;
}
diff --git a/src/tools/codeeditor/projectsearch.hpp b/src/tools/codeeditor/projectsearch.hpp
index 423bb5249..9797b2782 100644
--- a/src/tools/codeeditor/projectsearch.hpp
+++ b/src/tools/codeeditor/projectsearch.hpp
@@ -18,9 +18,12 @@ class ProjectSearch {
public:
struct ResultData {
struct Result {
- Result( const String& line, const TextRange& pos ) : line( line ), position( pos ) {}
+ Result( const String& line, const TextRange& pos, Int64 s, Int64 e ) :
+ line( line ), position( pos ), start( s ), end( e ) {}
String line;
TextRange position;
+ Int64 start;
+ Int64 end;
bool selected{ true };
};
std::string file;