Added multiline support for TextDocument::find and TextDocument::findLast.

This commit is contained in:
Martín Lucas Golini
2022-03-07 01:53:17 -03:00
parent 9780d2a585
commit c102bf580a
10 changed files with 362 additions and 91 deletions

View File

@@ -1,6 +1,26 @@
#include "docsearchcontroller.hpp"
#include "codeeditor.hpp"
static void replaceAllEscapedSequences( String& target, const String& that, const String& with ) {
std::string::size_type pos = 0;
while ( ( pos = target.find( that, pos ) ) != String::InvalidPos ) {
if ( pos > 0 && target[pos - 1] == '\\' ) {
target.erase( pos, 1 );
} else {
target.erase( pos, that.length() );
target.insert( pos, with );
}
pos += with.length();
}
}
static void escapeSequences( String& txt ) {
replaceAllEscapedSequences( txt, "\\n", String( '\n' ) );
replaceAllEscapedSequences( txt, "\\t", String( '\t' ) );
replaceAllEscapedSequences( txt, "\\r", String( '\r' ) );
replaceAllEscapedSequences( txt, "\\\\", String( '\\' ) );
}
DocSearchController::DocSearchController( UICodeEditorSplitter* editorSplitter, App* app ) :
mEditorSplitter( editorSplitter ), mApp( app ) {}
@@ -22,6 +42,7 @@ void DocSearchController::initSearchBar( UISearchBar* searchBar ) {
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
UITextInput* replaceInput = mSearchBarLayout->find<UITextInput>( "search_replace" );
UICheckBox* caseSensitiveChk = mSearchBarLayout->find<UICheckBox>( "case_sensitive" );
UICheckBox* escapeSequenceChk = mSearchBarLayout->find<UICheckBox>( "escape_sequence" );
UICheckBox* wholeWordChk = mSearchBarLayout->find<UICheckBox>( "whole_word" );
UICheckBox* luaPatternChk = mSearchBarLayout->find<UICheckBox>( "lua_pattern" );
@@ -30,6 +51,11 @@ void DocSearchController::initSearchBar( UISearchBar* searchBar ) {
mSearchState.caseSensitive = caseSensitiveChk->isChecked();
} );
escapeSequenceChk->addEventListener(
Event::OnValueChange, [&, escapeSequenceChk]( const Event* ) {
mSearchState.escapeSequences = escapeSequenceChk->isChecked();
} );
wholeWordChk->addEventListener( Event::OnValueChange, [&, wholeWordChk]( const Event* ) {
mSearchState.wholeWord = wholeWordChk->isChecked();
} );
@@ -88,16 +114,22 @@ void DocSearchController::initSearchBar( UISearchBar* searchBar ) {
mSearchBarLayout->addCommand( "change-whole-word", [&, wholeWordChk] {
wholeWordChk->setChecked( !wholeWordChk->isChecked() );
} );
mSearchBarLayout->addCommand( "change-escape-sequence", [&, escapeSequenceChk] {
escapeSequenceChk->setChecked( !escapeSequenceChk->isChecked() );
} );
mSearchBarLayout->addCommand( "toggle-lua-pattern", [&, luaPatternChk] {
luaPatternChk->setChecked( !luaPatternChk->isChecked() );
} );
mSearchBarLayout->getKeyBindings().addKeybindsString( { { "f3", "repeat-find" },
{ "ctrl+g", "repeat-find" },
{ "escape", "close-searchbar" },
{ "ctrl+r", "replace-all" },
{ "ctrl+s", "change-case" },
{ "ctrl+w", "change-whole-word" },
{ "ctrl+l", "toggle-lua-pattern" } } );
mSearchBarLayout->getKeyBindings().addKeybindsString(
{ { mApp->getKeybind( "repeat-find" ), "repeat-find" },
{ mApp->getKeybind( "find-prev" ), "find-prev" },
{ "ctrl+g", "repeat-find" },
{ "escape", "close-searchbar" },
{ "ctrl+r", "replace-all" },
{ "ctrl+s", "change-case" },
{ "ctrl+w", "change-whole-word" },
{ "ctrl+l", "toggle-lua-pattern" },
{ "ctrl+e", "change-escape-sequence" } } );
addReturnListener( findInput, "repeat-find" );
addReturnListener( replaceInput, "find-and-replace" );
addClickListener( mSearchBarLayout->find<UIPushButton>( "find_prev" ), "find-prev" );
@@ -123,6 +155,8 @@ void DocSearchController::showFindView() {
mSearchState.caseSensitive =
mSearchBarLayout->find<UICheckBox>( "case_sensitive" )->isChecked();
mSearchState.wholeWord = mSearchBarLayout->find<UICheckBox>( "whole_word" )->isChecked();
mSearchState.escapeSequences =
mSearchBarLayout->find<UICheckBox>( "escape_sequence" )->isChecked();
mSearchBarLayout->setEnabled( true )->setVisible( true );
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
@@ -156,6 +190,7 @@ bool DocSearchController::findPrevText( SearchState& search ) {
if ( !search.editor || !mEditorSplitter->editorExists( search.editor ) || search.text.empty() )
return false;
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
search.editor->getDocument().setActiveClient( search.editor );
mLastSearch = search.text;
TextDocument& doc = search.editor->getDocument();
@@ -166,18 +201,26 @@ bool DocSearchController::findPrevText( SearchState& search ) {
from = from < range.start() ? range.start() : from;
}
TextPosition found =
doc.findLast( search.text, from, search.caseSensitive, search.wholeWord, search.range );
String txt( search.text );
if ( search.escapeSequences )
escapeSequences( txt );
TextRange found = doc.findLast( txt, from, search.caseSensitive, search.wholeWord,
search.type, search.range );
if ( found.isValid() ) {
doc.setSelection( { doc.positionOffset( found, search.text.size() ), found } );
doc.setSelection( found );
findInput->removeClass( "error" );
return true;
} else {
found = doc.findLast( search.text, range.end() );
found = doc.findLast( txt, range.end(), search.caseSensitive, search.wholeWord,
search.type, range );
if ( found.isValid() ) {
doc.setSelection( { doc.positionOffset( found, search.text.size() ), found } );
doc.setSelection( found );
findInput->removeClass( "error" );
return true;
}
}
findInput->addClass( "error" );
return false;
}
@@ -187,6 +230,7 @@ bool DocSearchController::findNextText( SearchState& search ) {
if ( !search.editor || !mEditorSplitter->editorExists( search.editor ) || search.text.empty() )
return false;
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
search.editor->getDocument().setActiveClient( search.editor );
mLastSearch = search.text;
TextDocument& doc = search.editor->getDocument();
@@ -197,19 +241,26 @@ bool DocSearchController::findNextText( SearchState& search ) {
from = from < range.start() ? range.start() : from;
}
String txt( search.text );
if ( search.escapeSequences )
escapeSequences( txt );
TextRange found =
doc.find( search.text, from, search.caseSensitive, search.wholeWord, search.type, range );
doc.find( txt, from, search.caseSensitive, search.wholeWord, search.type, range );
if ( found.isValid() ) {
doc.setSelection( found.reversed() );
findInput->removeClass( "error" );
return true;
} else {
found = doc.find( search.text, range.start(), search.caseSensitive, search.wholeWord,
search.type, range );
found = doc.find( txt, range.start(), search.caseSensitive, search.wholeWord,
search.type, range );
if ( found.isValid() ) {
doc.setSelection( found.reversed() );
findInput->removeClass( "error" );
return true;
}
}
findInput->addClass( "error" );
return false;
}
@@ -233,8 +284,16 @@ int DocSearchController::replaceAll( SearchState& search, const String& replace
mLastSearch = search.text;
TextDocument& doc = search.editor->getDocument();
TextPosition startedPosition = doc.getSelection().start();
int count = doc.replaceAll( search.text, replace, search.caseSensitive, search.wholeWord,
search.type, search.range );
String txt( search.text );
String repl( replace );
if ( search.escapeSequences ) {
escapeSequences( txt );
escapeSequences( repl );
}
int count = doc.replaceAll( txt, repl, search.caseSensitive, search.wholeWord, search.type,
search.range );
doc.setSelection( startedPosition );
return count;
}
@@ -249,8 +308,16 @@ bool DocSearchController::findAndReplace( SearchState& search, const String& rep
search.editor->getDocument().setActiveClient( search.editor );
mLastSearch = search.text;
TextDocument& doc = search.editor->getDocument();
if ( doc.hasSelection() && doc.getSelectedText() == search.text ) {
return replaceSelection( search, replace );
String txt( search.text );
String repl( replace );
if ( search.escapeSequences ) {
escapeSequences( txt );
escapeSequences( repl );
}
if ( doc.hasSelection() && doc.getSelectedText() == txt ) {
return replaceSelection( search, repl );
} else {
return findNextText( search );
}