mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-25 15:53:11 +03:00
Plugin preferences configuration WIP.
This commit is contained in:
@@ -41,6 +41,8 @@
|
||||
--term-back-color: #1e2127;
|
||||
--term-font-color: #abb2bf;
|
||||
--highlight-primary: #FFFFFF7A;
|
||||
--disabled-color: #727679;
|
||||
--disabled-border: #43474c;
|
||||
droppable-hovering-color: #FFFFFF20;
|
||||
}
|
||||
|
||||
@@ -168,6 +170,12 @@ SelectButton:selectedpressed {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
pushbutton:disabled,
|
||||
selectbutton:disabled {
|
||||
color: var(--disabled-color);
|
||||
border-color: var(--disabled-border);
|
||||
}
|
||||
|
||||
PushButton::icon,
|
||||
SelectButton::icon,
|
||||
TableView::cell::icon,
|
||||
@@ -1030,6 +1038,8 @@ console {
|
||||
--floating-icon: #cbcdcd;
|
||||
--term-back-color: #eff0f1;
|
||||
--term-font-color: #232627;
|
||||
--disabled-color: #727679;
|
||||
--disabled-border: #d3d4d5;
|
||||
droppable-hovering-color: #00000020;
|
||||
}
|
||||
|
||||
@@ -1061,6 +1071,9 @@ listview::row:selected listview::cell::icon,
|
||||
tableview::row:selected tableview::cell::expander,
|
||||
treeview::row:selected treeview::cell::expander,
|
||||
listview::row:selected listview::cell::expander,
|
||||
tableview::row:selected tableview::cell checkbox,
|
||||
treeview::row:selected treeview::cell checkbox,
|
||||
listview::row:selected listview::cell checkbox,
|
||||
tableview::row:hover tableview::cell::text,
|
||||
treeview::row:hover treeview::cell::text,
|
||||
listview::row:hover listview::cell::text,
|
||||
@@ -1070,6 +1083,9 @@ listview::row:hover listview::cell::icon,
|
||||
tableview::row:hover tableview::cell::expander,
|
||||
treeview::row:hover treeview::cell::expander,
|
||||
listview::row:hover listview::cell::expander,
|
||||
tableview::row:hover tableview::cell checkbox,
|
||||
treeview::row:hover treeview::cell checkbox,
|
||||
listview::row:hover listview::cell checkbox,
|
||||
tableview::header::column:hover,
|
||||
treeview::header::column:hover,
|
||||
listview::header::column:hover {
|
||||
|
||||
@@ -93,17 +93,16 @@ void EventDispatcher::update( const Time& time ) {
|
||||
mNodeDragging->onCalculateDrag( mMousePos, mInput->getPressTrigger() );
|
||||
|
||||
if ( mInput->getPressTrigger() ) {
|
||||
if ( NULL != mOverNode ) {
|
||||
mOverNode->onMouseDown( mMousePosi, mInput->getPressTrigger() );
|
||||
sendMsg( mOverNode, NodeMessage::MouseDown, mInput->getPressTrigger() );
|
||||
}
|
||||
|
||||
if ( !mFirstPress ) {
|
||||
mDownNode = mOverNode;
|
||||
mMouseDownPos = mMousePosi;
|
||||
|
||||
mFirstPress = true;
|
||||
}
|
||||
|
||||
if ( NULL != mOverNode ) {
|
||||
mOverNode->onMouseDown( mMousePosi, mInput->getPressTrigger() );
|
||||
sendMsg( mOverNode, NodeMessage::MouseDown, mInput->getPressTrigger() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( mInput->getReleaseTrigger() ) {
|
||||
|
||||
@@ -1787,7 +1787,14 @@ void App::updateTerminalMenu() {
|
||||
}
|
||||
|
||||
void App::createPluginManagerUI() {
|
||||
UIPluginManager::New( mUISceneNode, mPluginManager.get() )->showWhenReady();
|
||||
UIPluginManager::New( mUISceneNode, mPluginManager.get(), [&]( const std::string& path ) {
|
||||
UITab* tab = mSplitter->isDocumentOpen( path );
|
||||
if ( !tab ) {
|
||||
loadFileFromPath( path );
|
||||
} else {
|
||||
tab->getTabWidget()->setTabSelected( tab );
|
||||
}
|
||||
} )->showWhenReady();
|
||||
}
|
||||
|
||||
void App::updateDocumentMenu() {
|
||||
|
||||
@@ -50,83 +50,125 @@ LinterPlugin::~LinterPlugin() {
|
||||
}
|
||||
}
|
||||
|
||||
void LinterPlugin::load( const PluginManager* pluginManager ) {
|
||||
std::string path( pluginManager->getResourcesPath() + "plugins/linters.json" );
|
||||
if ( FileSystem::fileExists( pluginManager->getPluginsPath() + "linters.json" ) )
|
||||
path = pluginManager->getPluginsPath() + "linters.json";
|
||||
if ( !FileSystem::fileExists( path ) )
|
||||
return;
|
||||
try {
|
||||
std::ifstream stream( path );
|
||||
json j;
|
||||
stream >> j;
|
||||
bool LinterPlugin::hasFileConfig() {
|
||||
return !mConfigPath.empty();
|
||||
}
|
||||
|
||||
for ( auto& obj : j ) {
|
||||
Linter linter;
|
||||
auto fp = obj["file_patterns"];
|
||||
std::string LinterPlugin::getFileConfigPath() {
|
||||
return mConfigPath;
|
||||
}
|
||||
|
||||
for ( auto& pattern : fp )
|
||||
linter.files.push_back( pattern.get<std::string>() );
|
||||
|
||||
auto wp = obj["warning_pattern"];
|
||||
|
||||
if ( wp.is_array() ) {
|
||||
for ( auto& warningPattern : wp )
|
||||
linter.warningPattern.push_back( warningPattern.get<std::string>() );
|
||||
} else {
|
||||
linter.warningPattern = { wp.get<std::string>() };
|
||||
}
|
||||
|
||||
linter.command = obj["command"].get<std::string>();
|
||||
|
||||
if ( obj.contains( "expected_exitcodes" ) ) {
|
||||
auto ee = obj["expected_exitcodes"];
|
||||
if ( ee.is_array() ) {
|
||||
for ( auto& number : ee )
|
||||
if ( number.is_number() )
|
||||
linter.expectedExitCodes.push_back( number.get<Int64>() );
|
||||
} else if ( ee.is_number() ) {
|
||||
linter.expectedExitCodes.push_back( ee.get<Int64>() );
|
||||
size_t LinterPlugin::linterFilePatternPosition( const std::vector<std::string>& patterns ) {
|
||||
for ( size_t i = 0; i < mLinters.size(); ++i ) {
|
||||
for ( const std::string& filePattern : mLinters[i].files ) {
|
||||
for ( const std::string& pattern : patterns ) {
|
||||
if ( filePattern == pattern ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
if ( obj.contains( "warning_pattern_order" ) ) {
|
||||
auto& wpo = obj["warning_pattern_order"];
|
||||
if ( wpo.contains( "line" ) && wpo["line"].is_number() )
|
||||
linter.warningPatternOrder.line = wpo["line"].get<int>();
|
||||
if ( wpo.contains( "col" ) && wpo["col"].is_number() )
|
||||
linter.warningPatternOrder.col = wpo["col"].get<int>();
|
||||
if ( wpo.contains( "message" ) && wpo["message"].is_number() )
|
||||
linter.warningPatternOrder.message = wpo["message"].get<int>();
|
||||
if ( wpo.contains( "type" ) && wpo["type"].is_number() )
|
||||
linter.warningPatternOrder.type = wpo["type"].get<int>();
|
||||
}
|
||||
void LinterPlugin::loadLinterConfig( const std::string& path ) {
|
||||
std::ifstream stream( path );
|
||||
json j;
|
||||
stream >> j;
|
||||
|
||||
if ( obj.contains( "column_starts_at_zero" ) )
|
||||
linter.columnsStartAtZero = obj["column_starts_at_zero"].get<bool>();
|
||||
for ( auto& obj : j ) {
|
||||
Linter linter;
|
||||
if ( !obj.contains( "file_patterns" ) || !obj.contains( "warning_pattern" ) ||
|
||||
!obj.contains( "command" ) )
|
||||
continue;
|
||||
|
||||
if ( obj.contains( "deduplicate" ) )
|
||||
linter.deduplicate = obj["deduplicate"].get<bool>();
|
||||
auto fp = obj["file_patterns"];
|
||||
|
||||
if ( obj.contains( "use_tmp_folder" ) )
|
||||
linter.useTmpFolder = obj["use_tmp_folder"].get<bool>();
|
||||
for ( auto& pattern : fp )
|
||||
linter.files.push_back( pattern.get<std::string>() );
|
||||
|
||||
if ( obj.contains( "no_errors_exit_code" ) &&
|
||||
obj["no_errors_exit_code"].is_number_integer() ) {
|
||||
linter.hasNoErrorsExitCode = true;
|
||||
linter.noErrorsExitCode = obj["no_errors_exit_code"].get<int>();
|
||||
}
|
||||
auto wp = obj["warning_pattern"];
|
||||
|
||||
mLinters.emplace_back( std::move( linter ) );
|
||||
if ( wp.is_array() ) {
|
||||
for ( auto& warningPattern : wp )
|
||||
linter.warningPattern.push_back( warningPattern.get<std::string>() );
|
||||
} else {
|
||||
linter.warningPattern = { wp.get<std::string>() };
|
||||
}
|
||||
|
||||
mReady = true;
|
||||
} catch ( json::exception& e ) {
|
||||
mReady = false;
|
||||
Log::error( "Parsing linter failed:\n%s", e.what() );
|
||||
linter.command = obj["command"].get<std::string>();
|
||||
|
||||
if ( obj.contains( "expected_exitcodes" ) ) {
|
||||
auto ee = obj["expected_exitcodes"];
|
||||
if ( ee.is_array() ) {
|
||||
for ( auto& number : ee )
|
||||
if ( number.is_number() )
|
||||
linter.expectedExitCodes.push_back( number.get<Int64>() );
|
||||
} else if ( ee.is_number() ) {
|
||||
linter.expectedExitCodes.push_back( ee.get<Int64>() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( obj.contains( "warning_pattern_order" ) ) {
|
||||
auto& wpo = obj["warning_pattern_order"];
|
||||
if ( wpo.contains( "line" ) && wpo["line"].is_number() )
|
||||
linter.warningPatternOrder.line = wpo["line"].get<int>();
|
||||
if ( wpo.contains( "col" ) && wpo["col"].is_number() )
|
||||
linter.warningPatternOrder.col = wpo["col"].get<int>();
|
||||
if ( wpo.contains( "message" ) && wpo["message"].is_number() )
|
||||
linter.warningPatternOrder.message = wpo["message"].get<int>();
|
||||
if ( wpo.contains( "type" ) && wpo["type"].is_number() )
|
||||
linter.warningPatternOrder.type = wpo["type"].get<int>();
|
||||
}
|
||||
|
||||
if ( obj.contains( "column_starts_at_zero" ) )
|
||||
linter.columnsStartAtZero = obj["column_starts_at_zero"].get<bool>();
|
||||
|
||||
if ( obj.contains( "deduplicate" ) )
|
||||
linter.deduplicate = obj["deduplicate"].get<bool>();
|
||||
|
||||
if ( obj.contains( "use_tmp_folder" ) )
|
||||
linter.useTmpFolder = obj["use_tmp_folder"].get<bool>();
|
||||
|
||||
if ( obj.contains( "no_errors_exit_code" ) &&
|
||||
obj["no_errors_exit_code"].is_number_integer() ) {
|
||||
linter.hasNoErrorsExitCode = true;
|
||||
linter.noErrorsExitCode = obj["no_errors_exit_code"].get<int>();
|
||||
}
|
||||
|
||||
// If the file pattern is repeated, we will overwrite the previous linter.
|
||||
// The previous linter should be the "default" linter that comes with ecode.
|
||||
size_t pos = linterFilePatternPosition( linter.files );
|
||||
if ( pos != std::string::npos ) {
|
||||
mLinters[pos] = linter;
|
||||
} else {
|
||||
mLinters.emplace_back( std::move( linter ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinterPlugin::load( const PluginManager* pluginManager ) {
|
||||
std::vector<std::string> paths;
|
||||
std::string path( pluginManager->getResourcesPath() + "plugins/linters.json" );
|
||||
if ( FileSystem::fileExists( path ) )
|
||||
paths.emplace_back( path );
|
||||
path = pluginManager->getPluginsPath() + "linters.json";
|
||||
if ( FileSystem::fileExists( path ) || FileSystem::fileWrite( path, "[]\n" ) ) {
|
||||
mConfigPath = path;
|
||||
paths.emplace_back( path );
|
||||
}
|
||||
if ( paths.empty() )
|
||||
return;
|
||||
for ( const auto& path : paths ) {
|
||||
try {
|
||||
loadLinterConfig( path );
|
||||
} catch ( json::exception& e ) {
|
||||
Log::error( "Parsing linter \"%s\" failed:\n%s", path.c_str(), e.what() );
|
||||
}
|
||||
}
|
||||
mReady = !mLinters.empty();
|
||||
}
|
||||
|
||||
void LinterPlugin::onRegister( UICodeEditor* editor ) {
|
||||
Lock l( mDocMutex );
|
||||
|
||||
|
||||
@@ -60,6 +60,10 @@ class LinterPlugin : public UICodeEditorPlugin {
|
||||
|
||||
std::string getDescription() { return Definition().description; }
|
||||
|
||||
bool hasFileConfig();
|
||||
|
||||
std::string getFileConfigPath();
|
||||
|
||||
void onRegister( UICodeEditor* );
|
||||
|
||||
void onUnregister( UICodeEditor* );
|
||||
@@ -94,6 +98,7 @@ class LinterPlugin : public UICodeEditorPlugin {
|
||||
std::mutex mWorkMutex;
|
||||
std::condition_variable mWorkerCondition;
|
||||
Int32 mWorkersCount{ 0 };
|
||||
std::string mConfigPath;
|
||||
|
||||
bool mReady{ false };
|
||||
bool mShuttingDown{ false };
|
||||
@@ -116,6 +121,10 @@ class LinterPlugin : public UICodeEditorPlugin {
|
||||
void invalidateEditors( TextDocument* doc );
|
||||
|
||||
std::string getMatchString( const LinterType& type );
|
||||
|
||||
void loadLinterConfig( const std::string& path );
|
||||
|
||||
size_t linterFilePatternPosition( const std::vector<std::string>& patterns );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "pluginmanager.hpp"
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/ui/uicheckbox.hpp>
|
||||
#include <eepp/ui/uitableview.hpp>
|
||||
#include <eepp/ui/uiwidgetcreator.hpp>
|
||||
@@ -171,7 +172,8 @@ class UIPluginManagerTable : public UITableView {
|
||||
}
|
||||
};
|
||||
|
||||
UIWindow* UIPluginManager::New( UISceneNode* sceneNode, PluginManager* manager ) {
|
||||
UIWindow* UIPluginManager::New( UISceneNode* sceneNode, PluginManager* manager,
|
||||
std::function<void( const std::string& )> loadFileCb ) {
|
||||
if ( !UIWidgetCreator::isWidgetRegistered( "UIPluginManagerTable" ) )
|
||||
UIWidgetCreator::registerWidget( "UIPluginManagerTable",
|
||||
[] { return eeNew( UIPluginManagerTable, () ); } );
|
||||
@@ -189,7 +191,7 @@ UIWindow* UIPluginManager::New( UISceneNode* sceneNode, PluginManager* manager )
|
||||
<UIPluginManagerTable id="plugin-manager-table" lw="mp" lh="fixed" layout_weight="1" />
|
||||
<vbox lw="mp" lh="wc">
|
||||
<hbox margin-top="4dp" layout-gravity="right">
|
||||
<!-- <pushbutton id="plugin-manager-preferences" enabled="false" text="Enabled" /> -->
|
||||
<pushbutton id="plugin-manager-preferences" enabled="false" text="Configuration" />
|
||||
<pushbutton id="plugin-manager-close" text="Close" icon="close" margin-left="4dp" />
|
||||
</hbox>
|
||||
</vbox>
|
||||
@@ -199,18 +201,40 @@ UIWindow* UIPluginManager::New( UISceneNode* sceneNode, PluginManager* manager )
|
||||
->asType<UIWindow>();
|
||||
UIWidget* cont = win->getContainer();
|
||||
UIPushButton* close = cont->find<UIPushButton>( "plugin-manager-close" );
|
||||
UIPushButton* prefs = cont->find<UIPushButton>( "plugin-manager-preferences" );
|
||||
UIPluginManagerTable* tv =
|
||||
win->getContainer()->find<UIPluginManagerTable>( "plugin-manager-table" );
|
||||
close->addEventListener( Event::MouseClick, [win]( const Event* event ) {
|
||||
const MouseEvent* mevent = static_cast<const MouseEvent*>( event );
|
||||
if ( mevent->getFlags() & EE_BUTTON_LMASK )
|
||||
if ( event->asMouseEvent()->getFlags() & EE_BUTTON_LMASK )
|
||||
win->closeWindow();
|
||||
} );
|
||||
prefs->setText( sceneNode->i18n( "preferences", "Preferences" ) );
|
||||
win->setTitle( sceneNode->i18n( "plugin_manager", "Plugin Manager" ) );
|
||||
tv->setModel( PluginsModel::New( manager ) );
|
||||
tv->setColumnsVisible(
|
||||
{ PluginsModel::Title, PluginsModel::Description, PluginsModel::Version } );
|
||||
tv->setAutoColumnsWidth( true );
|
||||
prefs->addEventListener( Event::MouseClick, [tv, manager, loadFileCb]( const Event* event ) {
|
||||
if ( event->asMouseEvent()->getFlags() & EE_BUTTON_LMASK &&
|
||||
!tv->getSelection().isEmpty() ) {
|
||||
const PluginDefinition* def =
|
||||
manager->getDefinitionIndex( tv->getSelection().first().row() );
|
||||
if ( def == nullptr || !manager->isEnabled( def->id ) )
|
||||
return;
|
||||
auto* plugin = manager->get( def->id );
|
||||
if ( !plugin->hasFileConfig() )
|
||||
return;
|
||||
if ( FileSystem::fileExists( plugin->getFileConfigPath() ) )
|
||||
loadFileCb( plugin->getFileConfigPath() );
|
||||
}
|
||||
} );
|
||||
tv->setOnSelection( [&, prefs, manager]( const ModelIndex& index ) {
|
||||
const PluginDefinition* def = manager->getDefinitionIndex( index.row() );
|
||||
if ( def == nullptr )
|
||||
return;
|
||||
prefs->setEnabled( manager->isEnabled( def->id ) &&
|
||||
manager->get( def->id )->hasFileConfig() );
|
||||
} );
|
||||
win->center();
|
||||
return win;
|
||||
}
|
||||
|
||||
@@ -99,14 +99,15 @@ class PluginsModel : public Model {
|
||||
|
||||
PluginManager* getManager() const;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
PluginManager* mManager;
|
||||
std::vector<std::string> mColumnNames{ "Id", "Title", "Enabled", "Description", "Version" };
|
||||
};
|
||||
|
||||
class UIPluginManager {
|
||||
public:
|
||||
static UIWindow* New( UISceneNode* sceneNode, PluginManager* manager );
|
||||
static UIWindow* New( UISceneNode* sceneNode, PluginManager* manager,
|
||||
std::function<void( const std::string& )> loadFileCb );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
Reference in New Issue
Block a user