21#include <magic_enum.hpp>
22#include <nlohmann/json.hpp>
25#include <wx/stdstream.h>
26#include <wx/wfstream.h>
39 type = magic_enum::enum_cast<PLUGIN_RUNTIME_TYPE>( aJson.at(
"type" ).get<std::string>(),
40 magic_enum::case_insensitive )
41 .value_or( PLUGIN_RUNTIME_TYPE::INVALID );
50 return type != PLUGIN_RUNTIME_TYPE::INVALID;
74 if( !aConfigFile.IsFileReadable() )
77 wxLogTrace(
traceApi,
"Plugin: parsing config file" );
79 wxFFileInputStream fp( aConfigFile.GetFullPath(), wxT(
"rt" ) );
80 wxStdInputStream fstream( fp );
86 js = nlohmann::json::parse( fstream,
nullptr,
92 wxLogTrace(
traceApi,
"Plugin: exception during parse" );
101 identifier = js.at(
"identifier" ).get<wxString>();
102 name = js.at(
"name" ).get<wxString>();
103 description = js.at(
"description" ).get<wxString>();
107 wxLogTrace(
traceApi,
"Plugin: error parsing runtime section" );
113 wxLogTrace(
traceApi,
"Plugin: exception while parsing required keys" );
118 wxRegEx identifierRegex( wxS(
"[\\w\\d]{2,}\\.[\\w\\d]+\\.[\\w\\d]+" ) );
122 wxLogTrace(
traceApi, wxString::Format(
"Plugin: identifier %s does not meet requirements",
131 const nlohmann::json& actionsJs = js.at(
"actions" );
133 if( actionsJs.is_array() )
135 for(
const nlohmann::json& actionJs : actionsJs )
139 a->identifier = wxString::Format(
"%s.%s",
identifier, a->identifier );
140 wxLogTrace(
traceApi, wxString::Format(
"Plugin: loaded action %s",
149 wxLogTrace(
traceApi,
"Plugin: exception while parsing actions" );
157 m_configFile( aConfigFile ),
217 action.
identifier = aJson.at(
"identifier" ).get<wxString>();
218 wxLogTrace(
traceApi, wxString::Format(
"Plugin: load action %s", action.
identifier ) );
219 action.
name = aJson.at(
"name" ).get<wxString>();
220 action.
description = aJson.at(
"description" ).get<wxString>();
221 action.
entrypoint = aJson.at(
"entrypoint" ).get<wxString>();
222 action.
show_button = aJson.contains(
"show-button" ) && aJson.at(
"show-button" ).get<
bool>();
226 wxLogTrace(
traceApi,
"Plugin: exception while parsing action required keys" );
232 if( !f.IsRelative() )
234 wxLogTrace(
traceApi, wxString::Format(
"Plugin: action contains abs path %s; skipping",
239 f.Normalize( wxPATH_NORM_ABSOLUTE,
m_configFile.GetPath() );
241 if( !f.IsFileReadable() )
243 wxLogTrace(
traceApi, wxString::Format(
"WARNING: action entrypoint %s is not readable",
247 if( aJson.contains(
"args" ) && aJson.at(
"args" ).is_array() )
249 for(
const nlohmann::json& argJs : aJson.at(
"args" ) )
253 action.
args.emplace_back( argJs.get<wxString>() );
257 wxLogTrace(
traceApi,
"Plugin: exception while parsing action args" );
263 if( aJson.contains(
"scopes" ) && aJson.at(
"scopes" ).is_array() )
265 for(
const nlohmann::json& scopeJs : aJson.at(
"scopes" ) )
269 action.
scopes.insert( magic_enum::enum_cast<PLUGIN_ACTION_SCOPE>(
270 scopeJs.get<std::string>(), magic_enum::case_insensitive )
271 .value_or( PLUGIN_ACTION_SCOPE::INVALID ) );
275 wxLogTrace(
traceApi,
"Plugin: exception while parsing action scopes" );
282 [&](
const std::string& aKey, wxBitmapBundle& aDest )
284 if( aJson.contains( aKey ) && aJson.at( aKey ).is_array() )
286 wxVector<wxBitmap> bitmaps;
288 for(
const nlohmann::json& iconJs : aJson.at( aKey ) )
294 iconFile = iconJs.get<wxString>();
301 iconFile.Normalize( wxPATH_NORM_ABSOLUTE,
m_configFile.GetPath() );
304 wxString::Format(
"Plugin: action %s: loading icon %s",
305 action.
identifier, iconFile.GetFullPath() ) );
308 if( !iconFile.IsFileReadable() )
310 wxLogTrace(
traceApi,
"Plugin: icon file could not be read" );
316 bmp.LoadFile( iconFile.GetFullPath(), wxBITMAP_TYPE_PNG );
319 bitmaps.push_back( bmp );
321 wxLogTrace(
traceApi,
"Plugin: icon file not a valid bitmap" );
324 aDest = wxBitmapBundle::FromBitmaps( bitmaps );
328 handleBitmap(
"icons-light", action.
icon_light );
329 handleBitmap(
"icons-dark", action.
icon_dark );
A plugin that is invoked by KiCad and runs as an external process; communicating with KiCad via the I...
const PLUGIN_RUNTIME & Runtime() const
API_PLUGIN(const wxFileName &aConfigFile)
const wxString & Name() const
const std::vector< PLUGIN_ACTION > & Actions() const
const wxString & Identifier() const
std::unique_ptr< API_PLUGIN_CONFIG > m_config
wxString BasePath() const
const wxString & Description() const
std::optional< PLUGIN_ACTION > createActionFromJson(const nlohmann::json &aJson)
const wxChar *const traceApi
Flag to enable debug output related to the API plugin system.
API_PLUGIN_CONFIG(API_PLUGIN &aParent, const wxFileName &aConfigFile)
std::vector< PLUGIN_ACTION > actions
An action performed by a plugin via the IPC API (not to be confused with ACTION_PLUGIN,...
wxBitmapBundle icon_light
std::set< PLUGIN_ACTION_SCOPE > scopes
std::vector< wxString > args
bool FromJson(const nlohmann::json &aJson)