Added XML tags auto-close.

This commit is contained in:
Martín Lucas Golini
2022-04-02 21:14:36 -03:00
parent 0e8b85dc46
commit aade7371f8
12 changed files with 1921 additions and 1814 deletions

View File

@@ -13,7 +13,7 @@ SyntaxDefinition::SyntaxDefinition( const std::string& languageName,
const std::string& comment,
const std::vector<std::string> headers ) :
mLanguageName( languageName ),
mLanguageId( String::hash( languageName ) ),
mLanguageId( String::hash( String::toLower( languageName ) ) ),
mFiles( files ),
mPatterns( patterns ),
mSymbols( symbols ),

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
#include <eepp/ui/doc/syntaxdefinitionmanager.hpp>
#include <eepp/ui/doc/syntaxhighlighter.hpp>
#include <eepp/ui/doc/syntaxtokenizer.hpp>
@@ -90,4 +91,20 @@ bool SyntaxHighlighter::updateDirty( int visibleLinesCount ) {
return false;
}
const SyntaxDefinition&
SyntaxHighlighter::getSyntaxDefinitionFromTextPosition( const TextPosition& position ) {
auto found = mLines.find( position.line() );
if ( found == mLines.end() )
return SyntaxDefinitionManager::instance()->getPlainStyle();
TokenizedLine& line = found->second;
SyntaxState state =
SyntaxTokenizer::retrieveSyntaxState( mDoc->getSyntaxDefinition(), line.state );
if ( nullptr == state.currentSyntax )
return SyntaxDefinitionManager::instance()->getPlainStyle();
return *state.currentSyntax;
}
}}} // namespace EE::UI::Doc

View File

@@ -61,14 +61,8 @@ std::pair<int, int> findNonEscaped( const std::string& text, const std::string&
}
}
struct SyntaxState {
const SyntaxDefinition* currentSyntax{ nullptr };
const SyntaxPattern* subsyntaxInfo{ nullptr };
Uint32 currentPatternIdx{ 0 };
Uint32 currentLevel{ 0 };
};
SyntaxState retrieveSyntaxState( const SyntaxDefinition& syntax, const Uint32& state ) {
SyntaxState SyntaxTokenizer::retrieveSyntaxState( const SyntaxDefinition& syntax,
const Uint32& state ) {
SyntaxState syntaxState{ &syntax, nullptr, state, 0 };
if ( state > 0 &&
( state > 255 ||

View File

@@ -766,6 +766,8 @@ Uint32 UICodeEditor::onTextInput( const TextInputEvent& event ) {
mDoc->textInput( event.getText() );
checkAutoCloseXMLTag( event.getText() );
for ( auto& module : mModules )
if ( module->onTextInput( this, event ) )
return 1;
@@ -2569,7 +2571,8 @@ Rectf UICodeEditor::getMinimapRect( const Vector2f& start ) const {
void UICodeEditor::drawMinimap( const Vector2f& start, const std::pair<int, int>& lineRange ) {
Float charHeight = PixelDensity::getPixelDensity() * mMinimapConfig.scale;
Float charSpacing = eemax( 1.f, eefloor( 0.8 * PixelDensity::getPixelDensity() * mMinimapConfig.scale ) );
Float charSpacing =
eemax( 1.f, eefloor( 0.8 * PixelDensity::getPixelDensity() * mMinimapConfig.scale ) );
Float lineSpacing = getMinimapLineSpacing();
Rectf rect( getMinimapRect( start ) );
int visibleLinesCount = ( lineRange.second - lineRange.first );
@@ -2756,4 +2759,45 @@ bool UICodeEditor::isMinimapFileTooLarge() const {
eefloor( getMinimapRect( getScreenStart() ).getHeight() / getMinimapLineSpacing() );
}
bool UICodeEditor::getAutoCloseXMLTags() const {
return mAutoCloseXMLTags;
}
void UICodeEditor::setAutoCloseXMLTags( bool autoCloseXMLTags ) {
mAutoCloseXMLTags = autoCloseXMLTags;
}
bool UICodeEditor::checkAutoCloseXMLTag( const String& text ) {
if ( !mAutoCloseXMLTags || text.empty() || text.size() > 1 || text[0] != '>' ||
mDoc->getSelection().hasSelection() )
return false;
TextPosition start( mDoc->getSelection().start() );
if ( start.line() >= (Int64)mDoc->linesCount() )
return false;
const auto& line = mDoc->line( start.line() ).getText();
if ( start.column() >= (Int64)line.size() )
return false;
if ( line[start.column() - 1] != '>' || ( line.size() > 2 && line[start.column() - 2] == '/' ) )
return false;
// Only close tags if the current line syntax is XML or HTML
const SyntaxDefinition& definition = mHighlighter.getSyntaxDefinitionFromTextPosition( start );
const String::HashType xmlType = String::hash( "xml" );
const String::HashType htmlType = String::hash( "html" );
if ( definition.getLanguageId() != xmlType && definition.getLanguageId() != htmlType )
return false;
size_t foundOpenPos = line.find_last_of( "<", start.column() - 1 );
if ( foundOpenPos == String::InvalidPos || start.column() - foundOpenPos < 1 )
return false;
std::string tag( line.substr( foundOpenPos, start.column() - foundOpenPos ).toUtf8() );
LuaPattern pattern( "<([%w_%-]+).*>" );
auto match = pattern.gmatch( tag );
if ( match.matches() ) {
std::string tagName( match.group( 1 ) );
mDoc->textInput( String( "</" + tagName + ">" ) );
mDoc->setSelection( start );
return true;
}
return false;
}
}} // namespace EE::UI

View File

@@ -98,6 +98,7 @@ void AppConfig::load( std::string& confPath, std::string& keybindingsPath,
ini.getValueB( "editor", "single_click_tree_navigation", false );
editor.syncProjectTreeWithEditor =
ini.getValueB( "editor", "sync_project_tree_with_editor", false );
editor.autoCloseXMLTags = ini.getValueB( "editor", "auto_close_xml_tags", true );
iniInfo = FileInfo( ini.path() );
}
@@ -164,6 +165,7 @@ void AppConfig::save( const std::vector<std::string>& recentFiles,
ini.setValueB( "editor", "hide_tab_bar_on_single_tab", editor.hideTabBarOnSingleTab );
ini.setValueB( "editor", "single_click_tree_navigation", editor.singleClickTreeNavigation );
ini.setValueB( "editor", "sync_project_tree_with_editor", editor.syncProjectTreeWithEditor );
ini.setValueB( "editor", "auto_close_xml_tags", editor.autoCloseXMLTags );
ini.writeFile();
iniState.writeFile();
}

View File

@@ -63,6 +63,7 @@ struct CodeEditorConfig {
bool hideTabBarOnSingleTab{ true };
bool singleClickTreeNavigation{ false };
bool syncProjectTreeWithEditor{ true };
bool autoCloseXMLTags{ true };
std::string autoCloseBrackets{ "" };
int indentWidth{ 4 };
int tabWidth{ 4 };

View File

@@ -916,7 +916,7 @@ UIMenu* App::createDocumentMenu() {
} );
UIPopUpMenu* bracketsMenu = UIPopUpMenu::New();
mDocMenu->addSubMenu( "Auto-Close Brackets", nullptr, bracketsMenu );
mDocMenu->addSubMenu( "Auto-Close Brackets & Tags", nullptr, bracketsMenu );
auto& closeBrackets = mConfig.editor.autoCloseBrackets;
auto shouldCloseCb = []( UIMenuItem* ) -> bool { return false; };
bracketsMenu->addCheckBox( "Brackets ()", closeBrackets.find( '(' ) != std::string::npos )
@@ -939,10 +939,20 @@ UIMenu* App::createDocumentMenu() {
bracketsMenu->addCheckBox( "Back Quotes ``", closeBrackets.find( '`' ) != std::string::npos )
->setOnShouldCloseCb( shouldCloseCb )
->setId( "``" );
bracketsMenu->addCheckBox( "Auto Close XML Tags", mConfig.editor.autoCloseXMLTags )
->setOnShouldCloseCb( shouldCloseCb )
->setId( "XML" );
bracketsMenu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) {
std::string id = event->getNode()->getId();
if ( event->getNode()->isType( UI_TYPE_MENUCHECKBOX ) ) {
UIMenuCheckBox* item = event->getNode()->asType<UIMenuCheckBox>();
if ( item->getId() == "XML" ) {
mConfig.editor.autoCloseXMLTags = item->isActive();
mEditorSplitter->forEachEditor( [&]( UICodeEditor* editor ) {
editor->setAutoCloseXMLTags( mConfig.editor.autoCloseXMLTags );
} );
return;
}
auto curPairs = String::split( mConfig.editor.autoCloseBrackets, ',' );
auto found = std::find( curPairs.begin(), curPairs.end(), id );
if ( item->isActive() ) {
@@ -1372,6 +1382,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
editor->setColorPreview( config.colorPreview );
editor->setFont( mFontMono );
editor->setMenuIconSize( mMenuIconSize );
editor->setAutoCloseXMLTags( config.autoCloseXMLTags );
doc.setAutoCloseBrackets( !mConfig.editor.autoCloseBrackets.empty() );
doc.setAutoCloseBracketsPairs( makeAutoClosePairs( mConfig.editor.autoCloseBrackets ) );
doc.setAutoDetectIndentType( config.autoDetectIndentType );