mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-09 00:09:32 +03:00
ecode: Added Code Formatter module. Improved Linter module.
This commit is contained in:
10
bin/assets/formatter/formatter.json
Normal file
10
bin/assets/formatter/formatter.json
Normal file
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"file_patterns": ["%.js$", "%.ts$"],
|
||||
"command": "prettier $FILENAME"
|
||||
},
|
||||
{
|
||||
"file_patterns": ["%.cpp$", "%.h$", "%.hpp$"],
|
||||
"command": "clang-format --style=file $FILENAME"
|
||||
}
|
||||
]
|
||||
@@ -251,6 +251,8 @@ class EE_API TextDocument {
|
||||
|
||||
void setCommand( const std::string& command, DocumentCommand func );
|
||||
|
||||
bool hasCommand( const std::string& command );
|
||||
|
||||
TextRange find( String text, TextPosition from = { 0, 0 }, const bool& caseSensitive = true,
|
||||
const bool& wholeWord = false,
|
||||
const FindReplaceType& type = FindReplaceType::Normal,
|
||||
|
||||
@@ -1103,6 +1103,8 @@
|
||||
../../src/tools/codeeditor/filelocator.hpp
|
||||
../../src/tools/codeeditor/filesystemlistener.cpp
|
||||
../../src/tools/codeeditor/filesystemlistener.hpp
|
||||
../../src/tools/codeeditor/formattermodule.cpp
|
||||
../../src/tools/codeeditor/formattermodule.hpp
|
||||
../../src/tools/codeeditor/globalsearchcontroller.cpp
|
||||
../../src/tools/codeeditor/globalsearchcontroller.hpp
|
||||
../../src/tools/codeeditor/ignorematcher.cpp
|
||||
|
||||
@@ -1246,6 +1246,10 @@ void TextDocument::setCommand( const std::string& command, TextDocument::Documen
|
||||
mCommands[command] = func;
|
||||
}
|
||||
|
||||
bool TextDocument::hasCommand( const std::string& command ) {
|
||||
return mCommands.find( command ) != mCommands.end();
|
||||
}
|
||||
|
||||
static std::pair<size_t, size_t> findType( const String& str, const String& findStr,
|
||||
const TextDocument::FindReplaceType& type ) {
|
||||
switch ( type ) {
|
||||
|
||||
@@ -70,6 +70,7 @@ void AppConfig::load( std::string& confPath, std::string& keybindingsPath,
|
||||
editor.colorPreview = ini.getValueB( "editor", "color_preview", true );
|
||||
editor.autoComplete = ini.getValueB( "editor", "auto_complete", true );
|
||||
editor.linter = ini.getValueB( "editor", "linter", true );
|
||||
editor.formatter = ini.getValueB( "editor", "formatter", true );
|
||||
editor.showDocInfo = ini.getValueB( "editor", "show_doc_info", true );
|
||||
editor.hideTabBarOnSingleTab = ini.getValueB( "editor", "hide_tab_bar_on_single_tab", true );
|
||||
editor.singleClickTreeNavigation = ini.getValueB( "editor", "single_click_tree_navigation", false );
|
||||
@@ -116,6 +117,7 @@ void AppConfig::save( const std::vector<std::string>& recentFiles,
|
||||
ini.setValueB( "editor", "color_preview", editor.colorPreview );
|
||||
ini.setValueB( "editor", "auto_complete", editor.autoComplete );
|
||||
ini.setValueB( "editor", "linter", editor.linter );
|
||||
ini.setValueB( "editor", "formatter", editor.formatter );
|
||||
ini.setValueB( "editor", "show_doc_info", editor.showDocInfo );
|
||||
ini.setValueB( "editor", "hide_tab_bar_on_single_tab", editor.hideTabBarOnSingleTab );
|
||||
ini.setValueB( "editor", "single_click_tree_navigation", editor.singleClickTreeNavigation );
|
||||
|
||||
@@ -51,6 +51,7 @@ struct CodeEditorConfig {
|
||||
bool autoComplete{ true };
|
||||
bool showDocInfo{ true };
|
||||
bool linter{ true };
|
||||
bool formatter{ true };
|
||||
bool hideTabBarOnSingleTab{ true };
|
||||
bool singleClickTreeNavigation{ false };
|
||||
std::string autoCloseBrackets{ "" };
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "codeeditor.hpp"
|
||||
#include "autocompletemodule.hpp"
|
||||
#include "formattermodule.hpp"
|
||||
#include "lintermodule.hpp"
|
||||
#include <algorithm>
|
||||
#include <args/args.hxx>
|
||||
@@ -372,6 +373,7 @@ App::~App() {
|
||||
eeSAFE_DELETE( mEditorSplitter );
|
||||
eeSAFE_DELETE( mAutoCompleteModule );
|
||||
eeSAFE_DELETE( mLinterModule );
|
||||
eeSAFE_DELETE( mFormatterModule );
|
||||
eeSAFE_DELETE( mConsole );
|
||||
if ( mFileWatcher )
|
||||
delete mFileWatcher;
|
||||
@@ -609,6 +611,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( "Enable Code Formatter" )
|
||||
->setActive( mConfig.editor.formatter )
|
||||
->setTooltipText( "Enables the code formatter/prettifier module." );
|
||||
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." );
|
||||
@@ -661,6 +666,8 @@ UIMenu* App::createViewMenu() {
|
||||
setAutoComplete( item->asType<UIMenuCheckBox>()->isActive() );
|
||||
} else if ( item->getText() == "Enable Linter" ) {
|
||||
setLinter( item->asType<UIMenuCheckBox>()->isActive() );
|
||||
} else if ( item->getText() == "Enable Code Formatter" ) {
|
||||
setFormatter( item->asType<UIMenuCheckBox>()->isActive() );
|
||||
} else if ( item->getText() == "Enable Color Preview" ) {
|
||||
mConfig.editor.colorPreview = item->asType<UIMenuCheckBox>()->isActive();
|
||||
mEditorSplitter->forEachEditor( [&]( UICodeEditor* editor ) {
|
||||
@@ -1100,7 +1107,8 @@ std::map<KeyBindings::Shortcut, std::string> App::getLocalKeybindings() {
|
||||
{ { KEY_L, KEYMOD_CTRL }, "go-to-line" },
|
||||
{ { KEY_M, KEYMOD_CTRL }, "menu-toggle" },
|
||||
{ { KEY_S, KEYMOD_CTRL | KEYMOD_SHIFT }, "save-all" },
|
||||
{ { KEY_F9, KEYMOD_LALT }, "switch-side-panel" } };
|
||||
{ { KEY_F9, KEYMOD_LALT }, "switch-side-panel" },
|
||||
{ { KEY_F, KEYMOD_LALT }, "format-doc" } };
|
||||
}
|
||||
|
||||
std::vector<std::string> App::getUnlockedCommands() {
|
||||
@@ -1403,8 +1411,14 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
|
||||
if ( config.linter && !mLinterModule )
|
||||
setLinter( config.linter );
|
||||
|
||||
if ( config.formatter && !mFormatterModule )
|
||||
setFormatter( config.formatter );
|
||||
|
||||
if ( config.linter && mLinterModule )
|
||||
editor->registerModule( mLinterModule );
|
||||
|
||||
if ( config.formatter && mFormatterModule )
|
||||
editor->registerModule( mFormatterModule );
|
||||
}
|
||||
|
||||
bool App::setAutoComplete( bool enable ) {
|
||||
@@ -1436,6 +1450,22 @@ bool App::setLinter( bool enable ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool App::setFormatter( bool enable ) {
|
||||
mConfig.editor.formatter = enable;
|
||||
if ( enable && !mFormatterModule ) {
|
||||
std::string path( mResPath + "assets/formatter/formatter.json" );
|
||||
if ( FileSystem::fileExists( mConfigPath + "formatter.json" ) )
|
||||
path = mConfigPath + "formatter.json";
|
||||
mFormatterModule = eeNew( FormatterModule, ( path, mThreadPool ) );
|
||||
mEditorSplitter->forEachEditor(
|
||||
[&]( UICodeEditor* editor ) { editor->registerModule( mFormatterModule ); } );
|
||||
return true;
|
||||
}
|
||||
if ( !enable && mFormatterModule )
|
||||
eeSAFE_DELETE( mFormatterModule );
|
||||
return false;
|
||||
}
|
||||
|
||||
void App::loadCurrentDirectory() {
|
||||
if ( !mEditorSplitter->getCurEditor() )
|
||||
return;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
class AutoCompleteModule;
|
||||
class LinterModule;
|
||||
class FormatterModule;
|
||||
|
||||
class App : public UICodeEditorSplitter::Client {
|
||||
public:
|
||||
@@ -101,6 +102,7 @@ class App : public UICodeEditorSplitter::Client {
|
||||
std::string mResPath;
|
||||
AutoCompleteModule* mAutoCompleteModule{ nullptr };
|
||||
LinterModule* mLinterModule{ nullptr };
|
||||
FormatterModule* mFormatterModule{ nullptr };
|
||||
std::shared_ptr<ThreadPool> mThreadPool;
|
||||
std::unique_ptr<ProjectDirectoryTree> mDirTree;
|
||||
UITreeView* mProjectTreeView{ nullptr };
|
||||
@@ -208,6 +210,8 @@ class App : public UICodeEditorSplitter::Client {
|
||||
|
||||
bool setLinter( bool enable );
|
||||
|
||||
bool setFormatter( bool enable );
|
||||
|
||||
void updateDocInfo( TextDocument& doc );
|
||||
|
||||
void setFocusEditorOnClose( UIMessageBox* msgBox );
|
||||
|
||||
150
src/tools/codeeditor/formattermodule.cpp
Normal file
150
src/tools/codeeditor/formattermodule.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#include "formattermodule.hpp"
|
||||
#include "thirdparty/json.hpp"
|
||||
#include "thirdparty/subprocess.h"
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ )
|
||||
#define FORMATTER_THREADED 1
|
||||
#else
|
||||
#define FORMATTER_THREADED 0
|
||||
#endif
|
||||
|
||||
FormatterModule::FormatterModule( const std::string& formattersPath,
|
||||
std::shared_ptr<ThreadPool> pool ) :
|
||||
mPool( pool ) {
|
||||
#if FORMATTER_THREADED
|
||||
mPool->run( [&, formattersPath] { load( formattersPath ); }, [] {} );
|
||||
#else
|
||||
load( formattersPath );
|
||||
#endif
|
||||
}
|
||||
|
||||
FormatterModule::~FormatterModule() {
|
||||
mClosing = true;
|
||||
for ( auto editor : mEditors )
|
||||
editor->unregisterModule( this );
|
||||
}
|
||||
|
||||
void FormatterModule::onRegister( UICodeEditor* editor ) {
|
||||
mEditors.insert( editor );
|
||||
|
||||
auto& doc = editor->getDocument();
|
||||
|
||||
if ( doc.hasCommand( "format-doc" ) )
|
||||
return;
|
||||
|
||||
doc.setCommand( "format-doc", [&, editor]() { formatDoc( editor ); } );
|
||||
}
|
||||
|
||||
void FormatterModule::onUnregister( UICodeEditor* editor ) {
|
||||
if ( mClosing )
|
||||
return;
|
||||
mEditors.erase( editor );
|
||||
}
|
||||
|
||||
void FormatterModule::load( const std::string& formatterPath ) {
|
||||
if ( !FileSystem::fileExists( formatterPath ) )
|
||||
return;
|
||||
try {
|
||||
std::ifstream stream( formatterPath );
|
||||
json j;
|
||||
stream >> j;
|
||||
|
||||
for ( auto& obj : j ) {
|
||||
Formatter formatter;
|
||||
auto fp = obj["file_patterns"];
|
||||
|
||||
for ( auto& pattern : fp )
|
||||
formatter.files.push_back( pattern.get<std::string>() );
|
||||
|
||||
formatter.command = obj["command"].get<std::string>();
|
||||
|
||||
if ( obj.contains( "type" ) ) {
|
||||
std::string typeStr( obj["type"].get<std::string>() );
|
||||
String::toLowerInPlace( typeStr );
|
||||
String::trimInPlace( typeStr );
|
||||
formatter.type =
|
||||
"inplace" == typeStr ? FormatterType::Inplace : FormatterType::Output;
|
||||
}
|
||||
|
||||
mFormatters.emplace_back( std::move( formatter ) );
|
||||
}
|
||||
|
||||
mReady = true;
|
||||
} catch ( json::exception& e ) {
|
||||
mReady = false;
|
||||
Log::error( "Parsing formatter failed:\n%s", e.what() );
|
||||
}
|
||||
}
|
||||
|
||||
void FormatterModule::formatDoc( UICodeEditor* editor ) {
|
||||
if ( !mReady )
|
||||
return;
|
||||
Clock clock;
|
||||
std::shared_ptr<TextDocument> doc = editor->getDocumentRef();
|
||||
auto formatter = supportsFormatter( doc );
|
||||
if ( formatter.command.empty() && doc->getFilePath().empty() )
|
||||
return;
|
||||
std::string cmd( formatter.command );
|
||||
std::string path( doc->getFilePath() );
|
||||
String::replaceAll( cmd, "$FILENAME", path );
|
||||
std::vector<std::string> cmdArr = String::split( cmd, ' ' );
|
||||
std::vector<const char*> strings;
|
||||
for ( size_t i = 0; i < cmdArr.size(); ++i )
|
||||
strings.push_back( cmdArr[i].c_str() );
|
||||
strings.push_back( NULL );
|
||||
struct subprocess_s subprocess;
|
||||
int result = subprocess_create( strings.data(),
|
||||
subprocess_option_inherit_environment |
|
||||
subprocess_option_combined_stdout_stderr,
|
||||
&subprocess );
|
||||
if ( 0 == result ) {
|
||||
std::string buffer( 1024, '\0' );
|
||||
std::string data;
|
||||
unsigned index = 0;
|
||||
unsigned bytesRead = 0;
|
||||
do {
|
||||
bytesRead = subprocess_read_stdout( &subprocess, &buffer[0], buffer.size() );
|
||||
index += bytesRead;
|
||||
data += buffer.substr( 0, bytesRead );
|
||||
} while ( bytesRead != 0 );
|
||||
|
||||
int ret;
|
||||
subprocess_join( &subprocess, &ret );
|
||||
subprocess_destroy( &subprocess );
|
||||
|
||||
// Log::info( "Formatter result:\n%s", data.c_str() );
|
||||
|
||||
if ( formatter.type == FormatterType::Output ) {
|
||||
editor->runOnMainThread( [&, data, editor]() {
|
||||
std::shared_ptr<TextDocument> doc = editor->getDocumentRef();
|
||||
TextPosition pos = doc->getSelection().start();
|
||||
doc->selectAll();
|
||||
doc->textInput( data );
|
||||
doc->setSelection( pos );
|
||||
} );
|
||||
}
|
||||
|
||||
Log::info( "FormatterModule::formatDoc for %s took %.2fms", path.c_str(),
|
||||
clock.getElapsedTime().asMilliseconds() );
|
||||
}
|
||||
}
|
||||
|
||||
FormatterModule::Formatter FormatterModule::supportsFormatter( std::shared_ptr<TextDocument> doc ) {
|
||||
std::string filePath( doc->getFilePath() );
|
||||
std::string extension( FileSystem::fileExtension( filePath ) );
|
||||
if ( extension.empty() )
|
||||
extension = FileSystem::fileNameFromPath( filePath );
|
||||
const auto& def = doc->getSyntaxDefinition();
|
||||
for ( auto& formatter : mFormatters ) {
|
||||
for ( auto& ext : formatter.files ) {
|
||||
auto& files = def.getFiles();
|
||||
if ( std::find( files.begin(), files.end(), ext ) != files.end() ) {
|
||||
return formatter;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
46
src/tools/codeeditor/formattermodule.hpp
Normal file
46
src/tools/codeeditor/formattermodule.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef FORMATTERMODULE_HPP
|
||||
#define FORMATTERMODULE_HPP
|
||||
|
||||
#include <eepp/config.hpp>
|
||||
#include <eepp/system/mutex.hpp>
|
||||
#include <eepp/system/threadpool.hpp>
|
||||
#include <eepp/ui/uicodeeditor.hpp>
|
||||
#include <set>
|
||||
using namespace EE;
|
||||
using namespace EE::System;
|
||||
using namespace EE::UI;
|
||||
|
||||
class FormatterModule : public UICodeEditorModule {
|
||||
public:
|
||||
FormatterModule( const std::string& formatterPath, std::shared_ptr<ThreadPool> pool );
|
||||
|
||||
virtual ~FormatterModule();
|
||||
|
||||
void onRegister( UICodeEditor* );
|
||||
|
||||
void onUnregister( UICodeEditor* );
|
||||
|
||||
protected:
|
||||
enum class FormatterType { Inplace, Output };
|
||||
|
||||
struct Formatter {
|
||||
std::vector<std::string> files;
|
||||
std::string command;
|
||||
FormatterType type{ FormatterType::Output };
|
||||
};
|
||||
|
||||
std::shared_ptr<ThreadPool> mPool;
|
||||
std::vector<Formatter> mFormatters;
|
||||
std::set<UICodeEditor*> mEditors;
|
||||
bool mClosing{ false };
|
||||
|
||||
bool mReady{ false };
|
||||
|
||||
void load( const std::string& formatterPath );
|
||||
|
||||
void formatDoc( UICodeEditor* editor );
|
||||
|
||||
FormatterModule::Formatter supportsFormatter( std::shared_ptr<TextDocument> doc );
|
||||
};
|
||||
|
||||
#endif // FORMATTERMODULE_HPP
|
||||
@@ -176,6 +176,8 @@ static std::string randString( size_t len ) {
|
||||
}
|
||||
|
||||
void LinterModule::lintDoc( std::shared_ptr<TextDocument> doc ) {
|
||||
if ( !mReady )
|
||||
return;
|
||||
auto linter = supportsLinter( doc );
|
||||
if ( linter.command.empty() )
|
||||
return;
|
||||
@@ -232,7 +234,7 @@ void LinterModule::runLinter( std::shared_ptr<TextDocument> doc, const Linter& l
|
||||
|
||||
// Log::info( "Linter result:\n%s", data.c_str() );
|
||||
|
||||
std::map<Int64, LinterMatch> matches;
|
||||
std::map<Int64, std::vector<LinterMatch>> matches;
|
||||
|
||||
for ( auto& warningPatterm : linter.warningPattern ) {
|
||||
LuaPattern pattern( warningPatterm );
|
||||
@@ -265,7 +267,7 @@ void LinterModule::runLinter( std::shared_ptr<TextDocument> doc, const Linter& l
|
||||
}
|
||||
linterMatch.pos = { line - 1, col > 0 ? col - 1 : 0 };
|
||||
linterMatch.lineCache = doc->line( line - 1 ).getHash();
|
||||
matches.insert( { line - 1, std::move( linterMatch ) } );
|
||||
matches[line - 1].emplace_back( std::move( linterMatch ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,42 +294,46 @@ void LinterModule::drawAfterLineText( UICodeEditor* editor, const Int64& index,
|
||||
}
|
||||
mMatchesMutex.unlock();
|
||||
|
||||
std::map<Int64, LinterMatch>& map = matchIt->second;
|
||||
std::map<Int64, std::vector<LinterMatch>>& map = matchIt->second;
|
||||
auto lineIt = map.find( index );
|
||||
if ( lineIt == map.end() )
|
||||
return;
|
||||
TextDocument* doc = matchIt->first;
|
||||
LinterMatch& match = lineIt->second;
|
||||
if ( match.lineCache != doc->line( index ).getHash() )
|
||||
return;
|
||||
Text line( "", editor->getFont(), editor->getFontSize() );
|
||||
line.setTabWidth( editor->getTabWidth() );
|
||||
line.setStyleConfig( editor->getFontStyleConfig() );
|
||||
line.setColor( editor->getColorScheme()
|
||||
.getEditorSyntaxStyle( match.type == LinterType::Warning ||
|
||||
match.type == LinterType::Notice
|
||||
? "warning"
|
||||
: "error" )
|
||||
.color );
|
||||
const String& text = doc->line( index ).getText();
|
||||
size_t minCol = text.find_first_not_of( " \t\f\v\n\r", match.pos.column() );
|
||||
if ( minCol == String::InvalidPos )
|
||||
minCol = match.pos.column();
|
||||
minCol = std::max( (Int64)minCol, match.pos.column() );
|
||||
if ( minCol >= text.size() )
|
||||
minCol = match.pos.column();
|
||||
if ( minCol >= text.size() )
|
||||
minCol = text.size() - 1;
|
||||
std::vector<LinterMatch>& matches = lineIt->second;
|
||||
for ( auto& match : matches ) {
|
||||
if ( match.lineCache != doc->line( index ).getHash() )
|
||||
return;
|
||||
Text line( "", editor->getFont(), editor->getFontSize() );
|
||||
line.setTabWidth( editor->getTabWidth() );
|
||||
line.setStyleConfig( editor->getFontStyleConfig() );
|
||||
line.setColor( editor->getColorScheme()
|
||||
.getEditorSyntaxStyle( match.type == LinterType::Warning ||
|
||||
match.type == LinterType::Notice
|
||||
? "warning"
|
||||
: "error" )
|
||||
.color );
|
||||
const String& text = doc->line( index ).getText();
|
||||
size_t minCol = text.find_first_not_of( " \t\f\v\n\r", match.pos.column() );
|
||||
if ( minCol == String::InvalidPos )
|
||||
minCol = match.pos.column();
|
||||
minCol = std::max( (Int64)minCol, match.pos.column() );
|
||||
if ( minCol >= text.size() )
|
||||
minCol = match.pos.column();
|
||||
if ( minCol >= text.size() )
|
||||
minCol = text.size() - 1;
|
||||
|
||||
std::string str( text.substr( minCol ).size() - 1, '~' );
|
||||
String string( str );
|
||||
line.setString( string );
|
||||
TextPosition endPos = doc->nextWordBoundary( { index, (Int64)minCol } );
|
||||
Int64 strSize = eemax( (Int64)0, static_cast<Int64>( endPos.column() - minCol ) );
|
||||
std::string str( strSize, '~' );
|
||||
String string( str );
|
||||
line.setString( string );
|
||||
|
||||
Vector2f pos( position.x + editor->getXOffsetCol( { match.pos.line(), (Int64)minCol } ),
|
||||
position.y );
|
||||
Rectf box( pos - editor->getScreenPos(), { editor->getTextWidth( string ), lineHeight } );
|
||||
match.box = box;
|
||||
line.draw( pos.x, pos.y + lineHeight * 0.5f );
|
||||
Vector2f pos( position.x + editor->getXOffsetCol( { match.pos.line(), (Int64)minCol } ),
|
||||
position.y );
|
||||
Rectf box( pos - editor->getScreenPos(), { editor->getTextWidth( string ), lineHeight } );
|
||||
match.box = box;
|
||||
line.draw( pos.x, pos.y + lineHeight * 0.5f );
|
||||
}
|
||||
}
|
||||
|
||||
bool LinterModule::onMouseMove( UICodeEditor* editor, const Vector2i& pos, const Uint32& ) {
|
||||
@@ -335,15 +341,17 @@ bool LinterModule::onMouseMove( UICodeEditor* editor, const Vector2i& pos, const
|
||||
if ( it != mMatches.end() ) {
|
||||
Vector2f localPos( editor->convertToNodeSpace( pos.asFloat() ) );
|
||||
for ( const auto& matchIt : it->second ) {
|
||||
auto& match = matchIt.second;
|
||||
if ( match.box.contains( localPos ) ) {
|
||||
editor->setTooltipText( match.text );
|
||||
editor->getTooltip()->setPixelsPosition( Vector2f( pos.x, pos.y ) );
|
||||
editor->runOnMainThread( [&, editor] { editor->getTooltip()->show(); } );
|
||||
return false;
|
||||
} else if ( editor->getTooltip() && editor->getTooltip()->isVisible() ) {
|
||||
editor->setTooltipText( "" );
|
||||
editor->getTooltip()->hide();
|
||||
auto& matches = matchIt.second;
|
||||
for ( const auto& match : matches ) {
|
||||
if ( match.box.contains( localPos ) ) {
|
||||
editor->setTooltipText( match.text );
|
||||
editor->getTooltip()->setPixelsPosition( Vector2f( pos.x, pos.y ) );
|
||||
editor->runOnMainThread( [&, editor] { editor->getTooltip()->show(); } );
|
||||
return false;
|
||||
} else if ( editor->getTooltip() && editor->getTooltip()->isVisible() ) {
|
||||
editor->setTooltipText( "" );
|
||||
editor->getTooltip()->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class LinterModule : public UICodeEditorModule {
|
||||
std::set<TextDocument*> mDocs;
|
||||
std::unordered_map<UICodeEditor*, TextDocument*> mEditorDocs;
|
||||
std::unordered_map<TextDocument*, std::unique_ptr<Clock>> mDirtyDoc;
|
||||
std::unordered_map<TextDocument*, std::map<Int64, LinterMatch>> mMatches;
|
||||
std::unordered_map<TextDocument*, std::map<Int64, std::vector<LinterMatch>>> mMatches;
|
||||
Time mDelayTime{ Seconds( 0.5f ) };
|
||||
Mutex mDocMutex;
|
||||
Mutex mMatchesMutex;
|
||||
|
||||
Reference in New Issue
Block a user