Fixed UITabWidget clipping.

Added pyw extension for python files.
ecode:
Added: Hide tabbar on single tab option.
Added whole word search in global search.
Some minor fixes in global search.
This commit is contained in:
Martín Lucas Golini
2020-12-23 02:46:46 -03:00
parent 07381c5943
commit dccd0617e5
11 changed files with 100 additions and 89 deletions

View File

@@ -89,6 +89,8 @@ class EE_API UICodeEditorSplitter {
void forEachDoc( std::function<void( TextDocument& doc )> run );
void forEachTabWidget( std::function<void( UITabWidget* )> run );
void zoomIn();
void zoomOut();
@@ -121,6 +123,10 @@ class EE_API UICodeEditorSplitter {
void forEachDocStoppable( std::function<bool( TextDocument& )> run );
bool getHideTabBarOnSingleTab() const;
void setHideTabBarOnSingleTab( bool hideTabBarOnSingleTab );
protected:
UISceneNode* mUISceneNode{ nullptr };
UICodeEditor* mCurEditor{ nullptr };
@@ -128,6 +134,7 @@ class EE_API UICodeEditorSplitter {
std::string mCurrentColorScheme;
std::vector<UITabWidget*> mTabWidgets;
Client* mClient;
bool mHideTabBarOnSingleTab{ true };
UICodeEditorSplitter( UICodeEditorSplitter::Client* client, UISceneNode* sceneNode,
const std::vector<SyntaxColorScheme>& colorSchemes,

View File

@@ -186,7 +186,7 @@ SyntaxDefinitionManager::SyntaxDefinitionManager() {
// Python
add( { "Python",
{ "%.py$" },
{ "%.py$", "%.pyw$" },
{
{ { "#", "\n" }, "comment" },
{ { "[ruU]?\"", "\"", "\\" }, "string" },

View File

@@ -352,7 +352,7 @@ UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent ) {
tabWidget->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
tabWidget->setParent( parent );
tabWidget->setTabsClosable( true );
tabWidget->setHideTabBarOnSingleTab( true );
tabWidget->setHideTabBarOnSingleTab( mHideTabBarOnSingleTab );
tabWidget->setAllowRearrangeTabs( true );
tabWidget->setAllowDragAndDropTabs( true );
tabWidget->addEventListener( Event::OnTabSelected, [&]( const Event* event ) {
@@ -408,6 +408,11 @@ void UICodeEditorSplitter::forEachDoc( std::function<void( TextDocument& )> run
run( *doc );
}
void UICodeEditorSplitter::forEachTabWidget( std::function<void( UITabWidget* )> run ) {
for ( auto widget : mTabWidgets )
run( widget );
}
void UICodeEditorSplitter::forEachEditorStoppable( std::function<bool( UICodeEditor* )> run ) {
for ( auto tabWidget : mTabWidgets ) {
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
@@ -432,6 +437,19 @@ void UICodeEditorSplitter::forEachDocStoppable( std::function<bool( TextDocument
}
}
bool UICodeEditorSplitter::getHideTabBarOnSingleTab() const {
return mHideTabBarOnSingleTab;
}
void UICodeEditorSplitter::setHideTabBarOnSingleTab( bool hideTabBarOnSingleTab ) {
if ( hideTabBarOnSingleTab != mHideTabBarOnSingleTab ) {
mHideTabBarOnSingleTab = hideTabBarOnSingleTab;
for ( auto widget : mTabWidgets )
widget->setHideTabBarOnSingleTab( hideTabBarOnSingleTab );
}
}
std::vector<UICodeEditor*> UICodeEditorSplitter::getAllEditors() {
std::vector<UICodeEditor*> editors;
forEachEditor( [&]( UICodeEditor* editor ) { editors.push_back( editor ); } );

View File

@@ -25,6 +25,7 @@ UITabWidget::UITabWidget() :
mAllowDragAndDropTabs( false ),
mTabVerticalDragResistance( PixelDensity::dpToPx( 64 ) ) {
setHorizontalAlign( UI_HALIGN_CENTER );
clipEnable();
mTabBar = UIWidget::NewWithTag( "tabwidget::tabbar" );
mTabBar->setPixelsSize( mSize.getWidth(), mStyleConfig.TabHeight )
@@ -37,7 +38,6 @@ UITabWidget::UITabWidget() :
mSize.getHeight() - PixelDensity::dpToPx( mStyleConfig.TabHeight ) )
->setParent( this )
->setPosition( 0, mStyleConfig.TabHeight );
mNodeContainer->clipEnable();
mTabScroll = UIScrollBar::NewHorizontalWithTag( "scrollbarmini" );
mTabScroll->setParent( this );

View File

@@ -71,6 +71,7 @@ void AppConfig::load( std::string& confPath, std::string& keybindingsPath,
editor.autoComplete = ini.getValueB( "editor", "auto_complete", true );
editor.linter = ini.getValueB( "editor", "linter", true );
editor.showDocInfo = ini.getValueB( "editor", "show_doc_info", true );
editor.hideTabBarOnSingleTab = ini.getValueB( "editor", "hide_tab_bar_on_single_tab", true );
}
void AppConfig::save( const std::vector<std::string>& recentFiles,
@@ -115,6 +116,7 @@ void AppConfig::save( const std::vector<std::string>& recentFiles,
ini.setValueB( "editor", "auto_complete", editor.autoComplete );
ini.setValueB( "editor", "linter", editor.linter );
ini.setValueB( "editor", "show_doc_info", editor.showDocInfo );
ini.setValueB( "editor", "hide_tab_bar_on_single_tab", editor.hideTabBarOnSingleTab );
ini.writeFile();
iniState.writeFile();
}

View File

@@ -51,6 +51,7 @@ struct CodeEditorConfig {
bool autoComplete{ true };
bool showDocInfo{ true };
bool linter{ true };
bool hideTabBarOnSingleTab{ true };
std::string autoCloseBrackets{ "" };
int indentWidth{ 4 };
int tabWidth{ 4 };

View File

@@ -582,6 +582,7 @@ void App::initSearchBar() {
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
UITextInput* replaceInput = mSearchBarLayout->find<UITextInput>( "search_replace" );
UICheckBox* caseSensitiveChk = mSearchBarLayout->find<UICheckBox>( "case_sensitive" );
UICheckBox* wholeWordChk = mSearchBarLayout->find<UICheckBox>( "whole_word" );
findInput->addEventListener( Event::OnTextChanged, [&, findInput]( const Event* ) {
if ( mSearchState.editor && mEditorSplitter->editorExists( mSearchState.editor ) ) {
mSearchState.text = findInput->getText();
@@ -627,12 +628,17 @@ void App::initSearchBar() {
caseSensitiveChk->setChecked( !caseSensitiveChk->isChecked() );
mSearchState.caseSensitive = caseSensitiveChk->isChecked();
} );
mSearchBarLayout->addCommand( "change-whole-word", [&, wholeWordChk] {
wholeWordChk->setChecked( !wholeWordChk->isChecked() );
mSearchState.wholeWord = wholeWordChk->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" },
} );
addReturnListener( findInput, "repeat-find" );
addReturnListener( replaceInput, "find-and-replace" );
@@ -704,11 +710,12 @@ void App::initGlobalSearchBar() {
};
UIPushButton* searchButton = mGlobalSearchBarLayout->find<UIPushButton>( "global_search" );
UICheckBox* caseSensitiveChk = mGlobalSearchBarLayout->find<UICheckBox>( "case_sensitive" );
UICheckBox* wholeWordChk = mGlobalSearchBarLayout->find<UICheckBox>( "whole_word" );
UIWidget* searchBarClose = mGlobalSearchBarLayout->find<UIWidget>( "global_searchbar_close" );
mGlobalSearchInput = mGlobalSearchBarLayout->find<UITextInput>( "global_search_find" );
mGlobalSearchHistoryList =
mGlobalSearchBarLayout->find<UIDropDownList>( "global_search_history" );
mGlobalSearchBarLayout->addCommand( "search-in-files", [&, caseSensitiveChk] {
mGlobalSearchBarLayout->addCommand( "search-in-files", [&, caseSensitiveChk, wholeWordChk] {
if ( mDirTree && mDirTree->getFilesCount() > 0 && !mGlobalSearchInput->getText().empty() ) {
UILoader* loader = UILoader::New();
loader->setId( "loader" );
@@ -720,7 +727,7 @@ void App::initGlobalSearchBar() {
mGlobalSearchTree->getSize() * 0.5f - loader->getSize() * 0.5f );
Clock* clock = eeNew( Clock, () );
std::string search( mGlobalSearchInput->getText().toUtf8() );
ProjectSearch::findHorspool(
ProjectSearch::find(
mDirTree->getFiles(), search,
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ )
mThreadPool,
@@ -763,7 +770,7 @@ void App::initGlobalSearchBar() {
loader->close();
} );
},
caseSensitiveChk->isChecked() );
caseSensitiveChk->isChecked(), wholeWordChk->isChecked() );
}
} );
mGlobalSearchBarLayout->addCommand( "close-global-searchbar", [&] {
@@ -774,10 +781,14 @@ void App::initGlobalSearchBar() {
mGlobalSearchBarLayout->getKeyBindings().addKeybindsString( {
{ "escape", "close-global-searchbar" },
{ "ctrl+s", "change-case" },
{ "ctrl+w", "change-whole-word" },
} );
mGlobalSearchBarLayout->addCommand( "change-case", [&, caseSensitiveChk] {
caseSensitiveChk->setChecked( !caseSensitiveChk->isChecked() );
} );
mGlobalSearchBarLayout->addCommand( "change-whole-word", [&, wholeWordChk] {
wholeWordChk->setChecked( !wholeWordChk->isChecked() );
} );
mGlobalSearchInput->addEventListener( Event::OnPressEnter, [&]( const Event* ) {
if ( mGlobalSearchInput->hasFocus() ) {
mGlobalSearchBarLayout->execute( "search-in-files" );
@@ -863,6 +874,7 @@ void App::showFindView() {
mSearchState.range = TextRange();
mSearchState.caseSensitive =
mSearchBarLayout->find<UICheckBox>( "case_sensitive" )->isChecked();
mSearchState.wholeWord = mSearchBarLayout->find<UICheckBox>( "whole_word" )->isChecked();
mSearchBarLayout->setEnabled( true )->setVisible( true );
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
@@ -1186,6 +1198,9 @@ UIMenu* App::createViewMenu() {
->setActive( mConfig.editor.linter )
->setTooltipText( "Use static code analysis tool used to flag programming errors, bugs,\n"
"stylistic errors, and suspicious constructs." );
mViewMenu->addCheckBox( "Hide tabbar on single tab" )
->setActive( mConfig.editor.hideTabBarOnSingleTab )
->setTooltipText( "Hides the tabbar if there's only one element in the tab widget." );
mViewMenu->add( "Line Breaking Column" );
mViewMenu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) {
@@ -1242,7 +1257,9 @@ UIMenu* App::createViewMenu() {
mDocInfo->setVisible( mConfig.editor.showDocInfo );
if ( mEditorSplitter->getCurEditor() )
updateDocInfo( mEditorSplitter->getCurEditor()->getDocument() );
} else if ( item->getText() == "Hide tabbar on single tab" ) {
mConfig.editor.hideTabBarOnSingleTab = item->asType<UIMenuCheckBox>()->isActive();
mEditorSplitter->setHideTabBarOnSingleTab( mConfig.editor.hideTabBarOnSingleTab );
} else if ( item->getText() == "Line Breaking Column" ) {
UIMessageBox* msgBox =
UIMessageBox::New( UIMessageBox::INPUT, "Set Line Breaking Column:\n"
@@ -2439,6 +2456,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
<PushButton id="find_prev" layout_width="wrap_content" layout_height="18dp" text="Previous" margin-right="4dp" />
<PushButton id="find_next" layout_width="wrap_content" layout_height="18dp" text="Next" margin-right="4dp" />
<CheckBox id="case_sensitive" layout_width="wrap_content" layout_height="wrap_content" text="Case sensitive" selected="true" />
<CheckBox id="whole_word" layout_width="wrap_content" layout_height="wrap_content" text="Match Whole Word" selected="false" margin-left="8dp" visible="false" />
<RelativeLayout layout_width="0" layout_weight="1" layout_height="18dp">
<Widget id="searchbar_close" class="close_button" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="center_vertical|right" margin-right="2dp" />
</RelativeLayout>
@@ -2461,6 +2479,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
<TextInput id="global_search_find" layout_width="match_parent" layout_height="wrap_content" layout_height="18dp" padding="0" margin-bottom="2dp" />
<hbox layout_width="match_parent" layout_height="wrap_content">
<CheckBox id="case_sensitive" layout_width="wrap_content" layout_height="wrap_content" text="Case sensitive" selected="true" />
<CheckBox id="whole_word" layout_width="wrap_content" layout_height="wrap_content" text="Match Whole Word" selected="false" margin-left="8dp" />
<Widget layout_width="0" layout_weight="1" layout_height="match_parent" />
<TextView layout_width="wrap_content" layout_height="wrap_content" text="History:" margin-right="4dp" layout_height="18dp" />
<DropDownList id="global_search_history" layout_width="300dp" layout_height="18dp" margin-right="4dp" />
@@ -2551,6 +2570,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
this, mUISceneNode,
SyntaxColorScheme::loadFromFile( mResPath + "assets/colorschemes/colorschemes.conf" ),
mInitColorScheme );
mEditorSplitter->setHideTabBarOnSingleTab( mConfig.editor.hideTabBarOnSingleTab );
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN
mFileWatcher = new efsw::FileWatcher();

View File

@@ -86,6 +86,7 @@ struct SearchState {
String text;
TextRange range = TextRange();
bool caseSensitive{ false };
bool wholeWord{ false };
void reset() {
editor = nullptr;
range = TextRange();

View File

@@ -15,7 +15,7 @@ static int countNewLines( const std::string& text, const size_t& start, const si
return count;
}
static std::string textLine( const std::string& fileText, const size_t& fromPos, size_t& relCol ) {
static String textLine( const std::string& fileText, const size_t& fromPos, size_t& relCol ) {
size_t start = 0;
size_t end = 0;
const char* stringStartPtr = fileText.c_str();
@@ -29,13 +29,20 @@ static std::string textLine( const std::string& fileText, const size_t& fromPos,
while ( ++ptr && *ptr != '\0' && *ptr != '\n' ) {
}
end = ptr - stringStartPtr;
relCol = startPtr - nlStartPtr;
relCol = String( fileText.substr( start, startPtr - nlStartPtr ) ).size();
return fileText.substr( start, end - start );
}
static bool isWholeWord( const std::string& fileText, const std::string& text,
const Int64& searchRes ) {
return ( 0 == searchRes || !( std::isalnum( fileText[searchRes - 1] ) ) ) &&
( searchRes + text.size() >= fileText.size() ||
!( std::isalnum( fileText[searchRes + text.size()] ) ) );
}
static std::vector<ProjectSearch::ResultData::Result>
searchInFileHorspool( const std::string& file, const std::string& text, const bool& caseSensitive,
const String::BMH::OccTable& occ ) {
const bool& wholeWord, const String::BMH::OccTable& occ ) {
std::vector<ProjectSearch::ResultData::Result> res;
std::string fileText;
Int64 lSearchRes = 0;
@@ -48,10 +55,15 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo
do {
searchRes = String::BMH::find( fileText, text, searchRes, occ );
if ( searchRes != -1 ) {
if ( wholeWord && !isWholeWord( fileText, text, searchRes ) ) {
lSearchRes = searchRes;
searchRes += text.size();
continue;
}
TextPosition pos;
size_t relCol;
totNl += countNewLines( fileText, lSearchRes, searchRes );
std::string str = textLine( fileTextOriginal, searchRes, relCol );
String str( textLine( fileTextOriginal, searchRes, relCol ) );
pos.setLine( totNl );
pos.setColumn( relCol );
res.push_back( { str, pos } );
@@ -63,6 +75,11 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo
do {
searchRes = String::BMH::find( fileText, text, searchRes, occ );
if ( searchRes != -1 ) {
if ( wholeWord && !isWholeWord( fileText, text, searchRes ) ) {
lSearchRes = searchRes;
searchRes += text.size();
continue;
}
TextPosition pos;
size_t relCol;
totNl += countNewLines( fileText, lSearchRes, searchRes );
@@ -78,43 +95,13 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo
return res;
}
static std::vector<ProjectSearch::ResultData::Result>
searchInFile( const std::string& file, const std::string& text, const bool& caseSensitive ) {
std::vector<ProjectSearch::ResultData::Result> res;
TextDocument doc( false );
TextPosition pos{ 0, 0 };
String searchText( text );
if ( doc.loadFromFile( file ) ) {
do {
pos = doc.find( searchText, pos, caseSensitive );
if ( pos.isValid() ) {
const auto& l = doc.line( pos.line() ).getText();
res.push_back( { l.substr( 0, l.size() - 1 ).toUtf8(), pos } );
pos = doc.positionOffset( pos, searchText.size() );
}
} while ( pos.isValid() );
}
return res;
}
void ProjectSearch::find( const std::vector<std::string> files, const std::string& string,
ResultCb result, bool caseSensitive ) {
Result res;
for ( auto& file : files ) {
auto fileRes = searchInFile( file, string, caseSensitive );
if ( !fileRes.empty() )
res.push_back( { file, fileRes } );
}
result( res );
}
void ProjectSearch::findHorspool( const std::vector<std::string> files, const std::string& string,
ResultCb result, bool caseSensitive ) {
ResultCb result, bool caseSensitive, bool wholeWord ) {
Result res;
const auto occ =
String::BMH::createOccTable( (const unsigned char*)string.c_str(), string.size() );
for ( auto& file : files ) {
auto fileRes = searchInFileHorspool( file, string, caseSensitive, occ );
auto fileRes = searchInFileHorspool( file, string, caseSensitive, wholeWord, occ );
if ( !fileRes.empty() )
res.push_back( { file, fileRes } );
}
@@ -129,38 +116,8 @@ struct FindData {
};
void ProjectSearch::find( const std::vector<std::string> files, std::string string,
std::shared_ptr<ThreadPool> pool, ResultCb result, bool caseSensitive ) {
if ( files.empty() )
result( {} );
FindData* findData = eeNew( FindData, () );
findData->resCount = files.size();
for ( auto& file : files ) {
pool->run(
[findData, file, string, caseSensitive] {
auto fileRes = searchInFile( file, string, caseSensitive );
if ( !fileRes.empty() ) {
Lock l( findData->resMutex );
findData->res.push_back( { file, fileRes } );
}
},
[result, findData] {
int count;
{
Lock l( findData->countMutex );
findData->resCount--;
count = findData->resCount;
}
if ( count == 0 ) {
result( findData->res );
eeDelete( findData );
}
} );
}
}
void ProjectSearch::findHorspool( const std::vector<std::string> files, std::string string,
std::shared_ptr<ThreadPool> pool, ResultCb result,
bool caseSensitive ) {
std::shared_ptr<ThreadPool> pool, ResultCb result, bool caseSensitive,
bool wholeWord ) {
if ( files.empty() )
result( {} );
FindData* findData = eeNew( FindData, () );
@@ -171,8 +128,8 @@ void ProjectSearch::findHorspool( const std::vector<std::string> files, std::str
String::BMH::createOccTable( (const unsigned char*)string.c_str(), string.size() );
for ( auto& file : files ) {
pool->run(
[findData, file, string, caseSensitive, occ] {
auto fileRes = searchInFileHorspool( file, string, caseSensitive, occ );
[findData, file, string, caseSensitive, wholeWord, occ] {
auto fileRes = searchInFileHorspool( file, string, caseSensitive, wholeWord, occ );
if ( !fileRes.empty() ) {
Lock l( findData->resMutex );
findData->res.push_back( { file, fileRes } );

View File

@@ -19,7 +19,7 @@ class ProjectSearch {
struct ResultData {
struct Result {
Result( const String& line, const TextPosition& pos ) : line( line ), position( pos ) {}
std::string line;
String line;
TextPosition position;
};
std::string file;
@@ -85,7 +85,10 @@ class ProjectSearch {
"%6lld %s",
mResult[index.internalId()].results[index.row()].position.line() +
1,
mResult[index.internalId()].results[index.row()].line.c_str() ) );
mResult[index.internalId()]
.results[index.row()]
.line.toUtf8()
.c_str() ) );
}
}
} else if ( role == Role::Custom ) {
@@ -123,17 +126,11 @@ class ProjectSearch {
}
static void find( const std::vector<std::string> files, const std::string& string,
ResultCb result, bool caseSensitive );
ResultCb result, bool caseSensitive, bool wholeWord = false );
static void find( const std::vector<std::string> files, std::string string,
std::shared_ptr<ThreadPool> pool, ResultCb result, bool caseSensitive );
static void findHorspool( const std::vector<std::string> files, const std::string& string,
ResultCb result, bool caseSensitive );
static void findHorspool( const std::vector<std::string> files, std::string string,
std::shared_ptr<ThreadPool> pool, ResultCb result,
bool caseSensitive );
std::shared_ptr<ThreadPool> pool, ResultCb result, bool caseSensitive,
bool wholeWord = false );
};
#endif // PROJECTSEARCH_HPP

View File

@@ -43,7 +43,15 @@ UIPushButton* UITreeViewCellGlobalSearch::updateText( const std::string& text )
mTextBox->setFontFillColor( pp->getLineNumColor(), from, to );
}
mSearchStrPos = { text.find( pp->getSearchStr() ), pp->getSearchStr().size() };
ModelIndex curIndex = getCurIndex();
ModelIndex index = pp->getModel()->index(
curIndex.row(), ProjectSearch::ResultModel::ColumnPosition, curIndex.parent() );
Variant variant = pp->getModel()->data( index, Model::Role::Custom );
Int64 iniPos = 0;
if ( variant.is( Variant::Type::Int64 ) )
iniPos = variant.asInt64();
String txt( text );
mSearchStrPos = { txt.find( pp->getSearchStr(), iniPos ), pp->getSearchStr().size() };
auto tokens =
SyntaxTokenizer::tokenize( styleDef, text, SYNTAX_TOKENIZER_STATE_NONE, to ).first;