21#include <magic_enum.hpp>
22#include <nlohmann/json.hpp>
25#include <wx/stdstream.h>
26#include <wx/wfstream.h>
40 type = magic_enum::enum_cast<PLUGIN_RUNTIME_TYPE>( aJson.at(
"type" ).get<std::string>(),
41 magic_enum::case_insensitive )
42 .value_or( PLUGIN_RUNTIME_TYPE::INVALID );
51 return type != PLUGIN_RUNTIME_TYPE::INVALID;
75 if( !aConfigFile.IsFileReadable() )
78 wxLogTrace(
traceApi,
"Plugin: parsing config file" );
80 wxFFileInputStream fp( aConfigFile.GetFullPath(), wxT(
"rt" ) );
81 wxStdInputStream fstream( fp );
87 js = nlohmann::json::parse( fstream,
nullptr,
93 wxLogTrace(
traceApi,
"Plugin: exception during parse" );
102 identifier = js.at(
"identifier" ).get<wxString>();
103 name = js.at(
"name" ).get<wxString>();
104 description = js.at(
"description" ).get<wxString>();
108 wxLogTrace(
traceApi,
"Plugin: error parsing runtime section" );
114 wxLogTrace(
traceApi,
"Plugin: exception while parsing required keys" );
119 wxRegEx identifierRegex( wxS(
"[\\w\\d]{2,}\\.[\\w\\d]+\\.[\\w\\d]+" ) );
123 wxLogTrace(
traceApi, wxString::Format(
"Plugin: identifier %s does not meet requirements",
132 const nlohmann::json& actionsJs = js.at(
"actions" );
134 if( actionsJs.is_array() )
136 for(
const nlohmann::json& actionJs : actionsJs )
140 a->identifier = wxString::Format(
"%s.%s",
identifier, a->identifier );
141 wxLogTrace(
traceApi, wxString::Format(
"Plugin: loaded action %s",
150 wxLogTrace(
traceApi,
"Plugin: exception while parsing actions" );
158 m_configFile( aConfigFile ),
225 action.
identifier = aJson.at(
"identifier" ).get<wxString>();
226 wxLogTrace(
traceApi, wxString::Format(
"Plugin: load action %s", action.
identifier ) );
227 action.
name = aJson.at(
"name" ).get<wxString>();
228 action.
description = aJson.at(
"description" ).get<wxString>();
229 action.
entrypoint = aJson.at(
"entrypoint" ).get<wxString>();
230 action.
show_button = aJson.contains(
"show-button" ) && aJson.at(
"show-button" ).get<
bool>();
234 wxLogTrace(
traceApi,
"Plugin: exception while parsing action required keys" );
240 if( !f.IsRelative() )
242 wxLogTrace(
traceApi, wxString::Format(
"Plugin: action contains abs path %s; skipping",
247 f.Normalize( wxPATH_NORM_ABSOLUTE,
m_configFile.GetPath() );
249 if( !f.IsFileReadable() )
251 wxLogTrace(
traceApi, wxString::Format(
"WARNING: action entrypoint %s is not readable",
255 if( aJson.contains(
"args" ) && aJson.at(
"args" ).is_array() )
257 for(
const nlohmann::json& argJs : aJson.at(
"args" ) )
261 action.
args.emplace_back( argJs.get<wxString>() );
265 wxLogTrace(
traceApi,
"Plugin: exception while parsing action args" );
271 if( aJson.contains(
"scopes" ) && aJson.at(
"scopes" ).is_array() )
273 for(
const nlohmann::json& scopeJs : aJson.at(
"scopes" ) )
277 action.
scopes.insert( magic_enum::enum_cast<PLUGIN_ACTION_SCOPE>(
278 scopeJs.get<std::string>(), magic_enum::case_insensitive )
279 .value_or( PLUGIN_ACTION_SCOPE::INVALID ) );
283 wxLogTrace(
traceApi,
"Plugin: exception while parsing action scopes" );
290 [&](
const std::string& aKey, wxBitmapBundle& aDest )
292 if( aJson.contains( aKey ) && aJson.at( aKey ).is_array() )
294 wxVector<wxBitmap> bitmaps;
296 for(
const nlohmann::json& iconJs : aJson.at( aKey ) )
302 iconFile = iconJs.get<wxString>();
309 iconFile.Normalize( wxPATH_NORM_ABSOLUTE,
m_configFile.GetPath() );
312 wxString::Format(
"Plugin: action %s: loading icon %s",
313 action.
identifier, iconFile.GetFullPath() ) );
316 if( !iconFile.IsFileReadable() )
318 wxLogTrace(
traceApi,
"Plugin: icon file could not be read" );
324 bmp.LoadFile( iconFile.GetFullPath(), wxBITMAP_TYPE_PNG );
327 bitmaps.push_back( bmp );
329 wxLogTrace(
traceApi,
"Plugin: icon file not a valid bitmap" );
332 aDest = wxBitmapBundle::FromBitmaps( bitmaps );
336 handleBitmap(
"icons-light", action.
icon_light );
337 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
wxString ActionSettingsKey(const PLUGIN_ACTION &aAction) 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 IPC API and its 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)