mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-30 01:56:31 +03:00
Fixes not reloading loaded document from an file system modified event after the first reload (SpartanJ/ecode#196).
Improved project search UI.
This commit is contained in:
@@ -206,6 +206,16 @@ ListView::cell::icon {
|
||||
margin-right: 4dp;
|
||||
}
|
||||
|
||||
CheckBox,
|
||||
RadioButton {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
CheckBox:focus,
|
||||
RadioButton:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
CheckBox::active,
|
||||
CheckBox::inactive {
|
||||
width: 12dp;
|
||||
|
||||
@@ -50,6 +50,7 @@ class EE_API Event {
|
||||
OnDocumentLoaded,
|
||||
OnDocumentChanged,
|
||||
OnDocumentClosed,
|
||||
OnDocumentReloaded,
|
||||
OnDocumentSyntaxDefinitionChange,
|
||||
OnDocumentDirtyOnFileSysten,
|
||||
OnFontStyleChanged,
|
||||
|
||||
@@ -251,6 +251,14 @@ class EE_API UIWidget : public UINode {
|
||||
|
||||
void setTabStop();
|
||||
|
||||
void unsetTabStop();
|
||||
|
||||
bool isTabFocusable() const;
|
||||
|
||||
void setTabFocusable();
|
||||
|
||||
void unsetTabFocusable();
|
||||
|
||||
UIWidget* getPrevTabWidget() const;
|
||||
|
||||
UIWidget* getNextTabWidget() const;
|
||||
|
||||
@@ -26,6 +26,7 @@ UICheckBox::UICheckBox( const std::string& tag ) :
|
||||
mActiveButton->setPosition( 0, 0 );
|
||||
mActiveButton->setSize( 8, 8 );
|
||||
mActiveButton->addEventListener( Event::OnSizeChange, cb );
|
||||
mActiveButton->unsetTabFocusable();
|
||||
|
||||
mInactiveButton = UIWidget::NewWithTag( tag + "::inactive" );
|
||||
mInactiveButton->setVisible( true );
|
||||
@@ -34,6 +35,7 @@ UICheckBox::UICheckBox( const std::string& tag ) :
|
||||
mInactiveButton->setPosition( 0, 0 );
|
||||
mInactiveButton->setSize( 8, 8 );
|
||||
mInactiveButton->addEventListener( Event::OnSizeChange, cb );
|
||||
mInactiveButton->unsetTabFocusable();
|
||||
|
||||
onPaddingChange();
|
||||
|
||||
|
||||
@@ -579,8 +579,10 @@ void UICodeEditor::onFontStyleChanged() {
|
||||
void UICodeEditor::onDocumentLoaded( TextDocument* ) {}
|
||||
|
||||
void UICodeEditor::onDocumentReloaded( TextDocument* ) {
|
||||
onDocumentClosed( mDoc.get() );
|
||||
onDocumentLoaded();
|
||||
DocEvent event( this, mDoc.get(), Event::OnDocumentReloaded );
|
||||
sendEvent( &event );
|
||||
invalidateDraw();
|
||||
invalidateLongestLineWidth();
|
||||
}
|
||||
|
||||
void UICodeEditor::onDocumentLoaded() {
|
||||
|
||||
@@ -24,6 +24,7 @@ UIRadioButton::UIRadioButton() :
|
||||
mActiveButton->setPosition( 0, 0 );
|
||||
mActiveButton->setSize( 8, 8 );
|
||||
mActiveButton->addEventListener( Event::OnSizeChange, cb );
|
||||
mActiveButton->unsetTabFocusable();
|
||||
|
||||
mInactiveButton = UIWidget::NewWithTag( "radiobutton::inactive" );
|
||||
mInactiveButton->setVisible( true );
|
||||
@@ -32,6 +33,7 @@ UIRadioButton::UIRadioButton() :
|
||||
mInactiveButton->setPosition( 0, 0 );
|
||||
mInactiveButton->setSize( 9, 8 );
|
||||
mInactiveButton->addEventListener( Event::OnSizeChange, cb );
|
||||
mInactiveButton->unsetTabFocusable();
|
||||
|
||||
onPaddingChange();
|
||||
|
||||
|
||||
@@ -1369,7 +1369,8 @@ std::vector<PropertyId> UIWidget::getPropertiesImplemented() const {
|
||||
PropertyId::BorderBottomLeftRadius,
|
||||
PropertyId::BorderBottomRightRadius,
|
||||
PropertyId::BorderSmooth,
|
||||
PropertyId::BackgroundSmooth };
|
||||
PropertyId::BackgroundSmooth,
|
||||
PropertyId::Focusable };
|
||||
}
|
||||
|
||||
std::string UIWidget::getPropertyString( const std::string& property ) const {
|
||||
@@ -1522,6 +1523,8 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef,
|
||||
return mBackground
|
||||
? ( mBackground->getBackgroundDrawable().isSmooth() ? "true" : "false" )
|
||||
: "false";
|
||||
case PropertyId::Focusable:
|
||||
return isTabFocusable() ? "true" : "false";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2063,6 +2066,22 @@ void UIWidget::setTabStop() {
|
||||
mFlags |= UI_TAB_STOP;
|
||||
}
|
||||
|
||||
void UIWidget::unsetTabStop() {
|
||||
mFlags &= ~UI_TAB_STOP;
|
||||
}
|
||||
|
||||
bool UIWidget::isTabFocusable() const {
|
||||
return ( mFlags & UI_TAB_FOCUSABLE ) != 0;
|
||||
}
|
||||
|
||||
void UIWidget::setTabFocusable() {
|
||||
mFlags |= UI_TAB_FOCUSABLE;
|
||||
}
|
||||
|
||||
void UIWidget::unsetTabFocusable() {
|
||||
mFlags &= ~UI_TAB_FOCUSABLE;
|
||||
}
|
||||
|
||||
UIWidget* UIWidget::getPrevWidget() const {
|
||||
UIWidget* found = NULL;
|
||||
UIWidget* possible = NULL;
|
||||
|
||||
@@ -504,12 +504,12 @@ R"html(
|
||||
</vbox>
|
||||
<vbox lw="0" lw8="1" lh="wc">
|
||||
<TextInput id="global_search_find" lw="mp" lh="wc" lh="18dp" padding="0" margin-bottom="2dp" />
|
||||
<hbox lw="mp" lh="wc" margin-bottom="4dp">
|
||||
<hbox lw="mp" lh="wc" margin-bottom="2dp">
|
||||
<TextInput id="global_search_where" lw="0" lw8="1" lh="wc" lh="18dp" padding="0" margin-right="4dp"
|
||||
hint='@string(search_where_example, "e.g. *.ts, src/**/include, -src/**/exclude")' hint-display="focus" />
|
||||
<PushButton lw="wc" lh="mp" text="..." />
|
||||
<PushButton id="global_search_filters_menu_button" lw="wc" lh="mp" text="..." />
|
||||
</hbox>
|
||||
<StackLayout lw="mp" lh="wc" margin-bottom="4dp">
|
||||
<StackLayout lw="mp" lh="wc" margin-bottom="2dp">
|
||||
<CheckBox id="case_sensitive" text='@string(case_sensitive, "Case sensitive")' selected="true" margin-right="8dp" />
|
||||
<CheckBox id="whole_word" text='@string(match_whole_word, "Match Whole Word")' selected="false" margin-right="8dp" />
|
||||
<CheckBox id="lua_pattern" text='@string(lua_pattern, "Lua Pattern")' selected="false" margin-right="8dp" />
|
||||
@@ -517,7 +517,7 @@ R"html(
|
||||
tooltip='@string(escape_sequence_tooltip, "Replace \\, \t, \n, \r and \uXXXX (Unicode characters) with the corresponding control")' />
|
||||
</StackLayout>
|
||||
<hbox lw="mp" lh="wc">
|
||||
<TextView text='@string(history, "History:")' margin-right="4dp" lh="18dp" />
|
||||
<TextView text='@string(history, "History:")' margin-right="4dp" lh="18dp" focusable="false" />
|
||||
<DropDownList id="global_search_history" lw="0" lh="18dp" lw8="1" margin-right="4dp" />
|
||||
<PushButton id="global_search_clear_history" lw="wc" lh="18dp" text='@string(clear_history, "Clear History")' margin-right="4dp" />
|
||||
<PushButton id="global_search" lw="wc" lh="18dp" text='@string(search, "Search")' margin-right="4dp" />
|
||||
|
||||
@@ -733,7 +733,8 @@ App::~App() {
|
||||
delete mFileWatcher;
|
||||
mFileWatcher = nullptr;
|
||||
}
|
||||
mDirTree->resetPluginManager();
|
||||
if ( mDirTree )
|
||||
mDirTree->resetPluginManager();
|
||||
mPluginManager.reset();
|
||||
eeSAFE_DELETE( mSplitter );
|
||||
|
||||
@@ -1948,10 +1949,13 @@ void App::onRealDocumentLoaded( UICodeEditor* editor, const std::string& path )
|
||||
}
|
||||
|
||||
TextDocument& doc = editor->getDocument();
|
||||
std::string filePath =
|
||||
doc.hasFilepath() ? doc.getFilePath()
|
||||
: ( !doc.getLoadingFilePath().empty() ? doc.getLoadingFilePath() : "" );
|
||||
|
||||
if ( mFileWatcher && doc.hasFilepath() &&
|
||||
( !mDirTree || !mDirTree->isDirInTree( doc.getFileInfo().getFilepath() ) ) ) {
|
||||
std::string dir( FileSystem::fileRemoveFileName( doc.getFileInfo().getFilepath() ) );
|
||||
if ( mFileWatcher && !filePath.empty() &&
|
||||
( !mDirTree || !mDirTree->isDirInTree( filePath ) ) ) {
|
||||
std::string dir( FileSystem::fileRemoveFileName( filePath ) );
|
||||
mThreadPool->run( [this, dir] {
|
||||
if ( mFileWatcher && !dirInFolderWatches( dir ) ) {
|
||||
auto watchId = mFileWatcher->addWatch( dir, mFileSystemListener );
|
||||
|
||||
@@ -232,6 +232,8 @@ void GlobalSearchController::initGlobalSearchBar(
|
||||
};
|
||||
mGlobalSearchInput->on( Event::OnPressEnter, pressEnterCb );
|
||||
mGlobalSearchWhereInput->on( Event::OnPressEnter, pressEnterCb );
|
||||
mGlobalSearchWhereInput->on( Event::OnTabNavigate,
|
||||
[this]( auto ) { mGlobalSearchInput->setFocus(); } );
|
||||
auto switchInputToTree = [this]( const Event* event ) {
|
||||
const KeyEvent* keyEvent = static_cast<const KeyEvent*>( event );
|
||||
Uint32 keyCode = keyEvent->getKeyCode();
|
||||
@@ -358,6 +360,36 @@ void GlobalSearchController::initGlobalSearchBar(
|
||||
keyEvent->getKeyCode() == KEY_RETURN )
|
||||
mGlobalSearchBarLayout->execute( "replace-in-files" );
|
||||
} );
|
||||
|
||||
UIWidget* menuBtn =
|
||||
mGlobalSearchBarLayout->find<UIWidget>( "global_search_filters_menu_button" );
|
||||
menuBtn->onClick( [this, menuBtn]( auto ) {
|
||||
UIPopUpMenu* menu = UIPopUpMenu::New();
|
||||
menu->add( mApp->i18n( "add_include_filter", "Add Include Filter" ) )
|
||||
->setId( "add-include-filter" );
|
||||
menu->add( mApp->i18n( "add_exclude_filter", "Add Exclude Filter" ) )
|
||||
->setId( "add-exclude-filter" );
|
||||
menu->on( Event::OnItemClicked, [this]( const Event* event ) {
|
||||
const auto& id = event->getNode()->getId();
|
||||
|
||||
String appendTxt = "";
|
||||
bool addComma = !mGlobalSearchWhereInput->getText().empty() &&
|
||||
mGlobalSearchWhereInput->getText().back() != ',';
|
||||
|
||||
if ( "add-include-filter" == id ) {
|
||||
appendTxt = ( addComma ? String{ "," } : String{ "" } ) + "*.txt";
|
||||
} else if ( "add-exclude-filter" == id ) {
|
||||
appendTxt = ( addComma ? String{ "," } : String{ "" } ) + "-*.txt";
|
||||
}
|
||||
|
||||
if ( !appendTxt.empty() )
|
||||
mGlobalSearchWhereInput->setText( mGlobalSearchWhereInput->getText() + appendTxt );
|
||||
} );
|
||||
|
||||
menu->showAtScreenPosition( menuBtn->convertToWorldSpace( { 0, 0 } ) );
|
||||
menu->setFocus();
|
||||
} );
|
||||
|
||||
mGlobalSearchTree = mGlobalSearchTreeSearch;
|
||||
}
|
||||
|
||||
|
||||
@@ -153,8 +153,12 @@ void ProjectSearch::find( const std::vector<std::string> files, const std::strin
|
||||
: std::vector<size_t>();
|
||||
for ( auto& file : files ) {
|
||||
bool skip = false;
|
||||
std::string_view fsv( file );
|
||||
if ( !basePath.empty() && String::startsWith( file, basePath ) )
|
||||
fsv = fsv.substr( basePath.size() );
|
||||
|
||||
for ( const auto& filter : pathFilters ) {
|
||||
bool matches = String::globMatch( file, filter.first );
|
||||
bool matches = String::globMatch( fsv, filter.first );
|
||||
if ( ( matches && filter.second ) || ( !matches && !filter.second ) ) {
|
||||
skip = true;
|
||||
break;
|
||||
@@ -186,82 +190,87 @@ void ProjectSearch::find( const std::vector<std::string> files, std::string stri
|
||||
if ( files.empty() )
|
||||
result( {} );
|
||||
FileSystem::dirAddSlashAtEnd( basePath );
|
||||
FindData* findData = eeNew( FindData, () );
|
||||
findData->resCount = files.size();
|
||||
if ( !caseSensitive )
|
||||
String::toLowerInPlace( string );
|
||||
const auto occ =
|
||||
type == TextDocument::FindReplaceType::Normal
|
||||
? String::BMH::createOccTable( (const unsigned char*)string.c_str(), string.size() )
|
||||
: std::vector<size_t>();
|
||||
std::vector<bool> search;
|
||||
search.resize( files.size() );
|
||||
size_t pos = 0;
|
||||
size_t count = 0;
|
||||
for ( const auto& file : files ) {
|
||||
bool skip = false;
|
||||
std::string_view fsv( file );
|
||||
if ( !basePath.empty() && String::startsWith( file, basePath ) )
|
||||
fsv = fsv.substr( basePath.size() );
|
||||
pool->run( [files = std::move( files ), string = std::move( string ), pool = std::move( pool ),
|
||||
result = std::move( result ), caseSensitive, wholeWord, type,
|
||||
pathFilters = std::move( pathFilters ),
|
||||
basePath = std::move( basePath )]() mutable {
|
||||
FindData* findData = eeNew( FindData, () );
|
||||
findData->resCount = files.size();
|
||||
if ( !caseSensitive )
|
||||
String::toLowerInPlace( string );
|
||||
const auto occ =
|
||||
type == TextDocument::FindReplaceType::Normal
|
||||
? String::BMH::createOccTable( (const unsigned char*)string.c_str(), string.size() )
|
||||
: std::vector<size_t>();
|
||||
std::vector<bool> search;
|
||||
search.resize( files.size() );
|
||||
size_t pos = 0;
|
||||
size_t count = 0;
|
||||
for ( const auto& file : files ) {
|
||||
bool skip = false;
|
||||
std::string_view fsv( file );
|
||||
if ( !basePath.empty() && String::startsWith( file, basePath ) )
|
||||
fsv = fsv.substr( basePath.size() );
|
||||
|
||||
for ( const auto& filter : pathFilters ) {
|
||||
bool matches = String::globMatch( fsv, filter.first );
|
||||
if ( ( matches && filter.second ) || ( !matches && !filter.second ) ) {
|
||||
skip = true;
|
||||
break;
|
||||
for ( const auto& filter : pathFilters ) {
|
||||
bool matches = String::globMatch( fsv, filter.first );
|
||||
if ( ( matches && filter.second ) || ( !matches && !filter.second ) ) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( skip ) {
|
||||
search[pos++] = false;
|
||||
continue;
|
||||
}
|
||||
search[pos++] = true;
|
||||
count++;
|
||||
}
|
||||
if ( skip ) {
|
||||
search[pos++] = false;
|
||||
continue;
|
||||
|
||||
findData->resCount = count;
|
||||
|
||||
if ( count == 0 ) {
|
||||
result( findData->res );
|
||||
eeDelete( findData );
|
||||
return;
|
||||
}
|
||||
search[pos++] = true;
|
||||
count++;
|
||||
}
|
||||
|
||||
findData->resCount = count;
|
||||
|
||||
if ( count == 0 ) {
|
||||
result( findData->res );
|
||||
eeDelete( findData );
|
||||
return;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
for ( const auto& file : files ) {
|
||||
if ( !search[pos] ) {
|
||||
pos = 0;
|
||||
for ( const auto& file : files ) {
|
||||
if ( !search[pos] ) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
|
||||
pool->run(
|
||||
[findData, file, string, caseSensitive, wholeWord, occ, type] {
|
||||
auto fileRes =
|
||||
type == TextDocument::FindReplaceType::Normal
|
||||
? searchInFileHorspool( file, string, caseSensitive, wholeWord, occ )
|
||||
: searchInFileLuaPattern( file, string, caseSensitive, wholeWord );
|
||||
if ( !fileRes.empty() ) {
|
||||
Lock l( findData->resMutex );
|
||||
findData->res.push_back( { file, fileRes } );
|
||||
}
|
||||
},
|
||||
[result, findData]( const auto& ) {
|
||||
int count;
|
||||
{
|
||||
Lock l( findData->countMutex );
|
||||
findData->resCount--;
|
||||
count = findData->resCount;
|
||||
}
|
||||
if ( count == 0 ) {
|
||||
result( findData->res );
|
||||
eeDelete( findData );
|
||||
pool->run(
|
||||
[findData, file, string, caseSensitive, wholeWord, occ, type] {
|
||||
auto fileRes =
|
||||
type == TextDocument::FindReplaceType::Normal
|
||||
? searchInFileHorspool( file, string, caseSensitive, wholeWord, occ )
|
||||
: searchInFileLuaPattern( file, string, caseSensitive, wholeWord );
|
||||
if ( !fileRes.empty() ) {
|
||||
Lock l( findData->resMutex );
|
||||
findData->res.push_back( { file, fileRes } );
|
||||
}
|
||||
},
|
||||
[result, findData]( const auto& ) {
|
||||
int count;
|
||||
{
|
||||
Lock l( findData->countMutex );
|
||||
findData->resCount--;
|
||||
count = findData->resCount;
|
||||
}
|
||||
if ( count == 0 ) {
|
||||
result( findData->res );
|
||||
eeDelete( findData );
|
||||
#if EE_PLATFORM == EE_PLATFORM_LINUX
|
||||
malloc_trim( 0 );
|
||||
malloc_trim( 0 );
|
||||
#endif
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void ProjectSearch::ResultModel::removeLastNewLineCharacter() {
|
||||
|
||||
Reference in New Issue
Block a user