WIP: dynamic definition of macro categories (currently: drc, lvs)

This commit is contained in:
Matthias Koefferlein 2022-02-19 17:57:41 +01:00
parent ff3bc38aea
commit 30f774f055
9 changed files with 132 additions and 57 deletions

View File

@ -158,6 +158,11 @@ module DRC
# Register the new interpreters
DRCInterpreter::new(drc_recipe)
DRCPlainTextInterpreter::new(drc_recipe)
# Creates a new macro category
if RBA::Application::instance
RBA::Application::instance.add_macro_category("drc", "DRC", [ "drc" ])
end
end
</text>

View File

@ -87,6 +87,12 @@ static std::string version (C *)
return C::version ();
}
template <class C>
static void add_macro_category (C *c, const std::string &name, const std::string &description, const std::vector<std::string> &folders)
{
c->add_macro_category (name, description, folders);
}
template <class C>
static gsi::Methods application_methods ()
{
@ -226,6 +232,12 @@ static gsi::Methods application_methods ()
"@brief Returns the architecture string\n"
"This method has been introduced in version 0.25."
) +
method_ext<C, const std::string &, const std::string &, const std::vector<std::string> &> ("add_macro_category", &add_macro_category<C>, gsi::arg ("name"), gsi::arg ("description"), gsi::arg ("folders"),
"@brief Creates a new macro category\n"
"Creating a new macro category is only possible during the autorun_early stage. "
"The new macro category must correspond to an interpreter registered at the same stage.\n"
"This method has been introduced in version 0.28."
) +
method<C *> ("instance", &C::instance,
"@brief Return the singleton instance of the application\n"
"\n"

View File

@ -686,6 +686,22 @@ ApplicationBase::init_app ()
if (mc) {
// create the basic macro categories
if (ruby_interpreter ().available ()) {
std::vector<std::string> folders;
folders.push_back ("macros");
folders.push_back ("ruby");
mc->add_macro_category ("macros", "Ruby", folders);
}
if (python_interpreter ().available ()) {
std::vector<std::string> folders;
folders.push_back ("pymacros");
folders.push_back ("python");
mc->add_macro_category ("pymacros", "Python", folders);
}
mc->enable_implicit_macros (! m_no_macros);
// Add the global ruby modules as the first ones.
@ -741,13 +757,29 @@ ApplicationBase::init_app ()
}
}
std::set<std::string> already_executed;
// run all early autorun macros
lym::MacroCollection::root ().autorun_early ();
lym::MacroCollection::root ().autorun_early (&already_executed);
// autorun_early may have added macro categories, so we need to call finish() again
if (mc) {
mc->finish ();
// as this regenerates the macro collection, autorun_early is required again
// note: this does no re-execute macros that have been executed already
lym::MacroCollection::root ().autorun_early (&already_executed);
}
// rescan the folders because early autorun macros might have added
// suffixes through the MacroInterpreter interface.
lym::MacroCollection::root ().rescan ();
// and yet another autorun_early pass ..
lym::MacroCollection::root ().autorun_early (&already_executed);
// creates the main window or plugin root as required
setup ();
@ -785,6 +817,15 @@ ApplicationBase::init_app ()
}
}
void
ApplicationBase::add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders)
{
lay::MacroController *mc = lay::MacroController::instance ();
if (mc) {
mc->add_macro_category (name, description, folders);
}
}
ApplicationBase::~ApplicationBase ()
{
tl::set_ui_exception_handlers (0, 0, 0);

View File

@ -214,6 +214,13 @@ public:
return *mp_python_interpreter;
}
/**
* @brief Adds a new macro category
*
* This method is only effective when called during the autorun_early stage
*/
void add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders);
/**
* @brief Return true, if undo buffering is enabled
*/

View File

@ -49,62 +49,27 @@ MacroController::MacroController ()
// .. nothing yet ..
}
static lay::MacroController::MacroCategory ruby_cat ()
void
MacroController::add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders)
{
lay::MacroController::MacroCategory cat;
cat.name = "macros";
cat.description = tl::to_string (QObject::tr ("Ruby"));
cat.folders.push_back ("macros");
cat.folders.push_back ("ruby");
return cat;
}
static lay::MacroController::MacroCategory python_cat ()
{
lay::MacroController::MacroCategory cat;
cat.name = "pymacros";
cat.description = tl::to_string (QObject::tr ("Python"));
cat.folders.push_back ("pymacros");
cat.folders.push_back ("python");
return cat;
}
static lay::MacroController::MacroCategory drc_cat ()
{
lay::MacroController::MacroCategory cat;
cat.name = "drc";
cat.description = tl::to_string (QObject::tr ("DRC"));
cat.folders.push_back ("drc");
return cat;
}
static lay::MacroController::MacroCategory lvs_cat ()
{
lay::MacroController::MacroCategory cat;
cat.name = "lvs";
cat.description = tl::to_string (QObject::tr ("LVS"));
cat.folders.push_back ("lvs");
return cat;
cat.name = name;
cat.description = description;
cat.folders = folders;
m_macro_categories.push_back (cat);
}
void
MacroController::finish ()
{
lym::MacroCollection::root ().clear ();
// Scan built-in macros
// These macros are always taken, even if there are no macros requested (they are required to
// fully form the API).
lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-macros", "macros", true);
lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-pymacros", "pymacros", true);
// TODO: consider adding "drc" and "lvs" dynamically and allow more dynamic categories
// We can do so if we first load the macros with the initial interpreters, then do autorun (which creates DSL interpreters) and then
// register the remaining categories.
m_macro_categories.push_back (ruby_cat ());
m_macro_categories.push_back (python_cat ());
m_macro_categories.push_back (drc_cat ());
m_macro_categories.push_back (lvs_cat ());
// scans the macros from techs and packages (this will allow autorun-early on them)
// and updates m_external_paths
sync_macro_sources ();

View File

@ -147,10 +147,16 @@ public:
/**
* @brief Loads the macros from the predefined paths and establishes the search paths
* This method will also establish the macro categories.
* This method can be called multiple times.
*/
void finish ();
/**
* @brief Adds a new macro category
* finish() needs to be called after adding a new category.
*/
void add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders);
/**
* @brief Adds a temporary macro
*

View File

@ -159,6 +159,11 @@ module LVS
LVSInterpreter::new(lvs_recipe)
LVSPlainTextInterpreter::new(lvs_recipe)
# Creates a new macro category
if RBA::Application::instance
RBA::Application::instance.add_macro_category("lvs", "LVS", [ "lvs" ])
end
end
</text>
</klayout-macro>

View File

@ -46,6 +46,8 @@
#include <fstream>
#include <memory>
#include <string>
#include <set>
namespace lym
{
@ -1065,6 +1067,11 @@ MacroCollection::MacroCollection ()
}
MacroCollection::~MacroCollection ()
{
do_clear ();
}
void MacroCollection::do_clear ()
{
for (iterator m = begin (); m != end (); ++m) {
delete m->second;
@ -1513,6 +1520,13 @@ void MacroCollection::scan (const std::string &path)
}
}
void MacroCollection::clear ()
{
begin_changes ();
do_clear ();
on_changed ();
}
void MacroCollection::erase (lym::Macro *mp)
{
for (iterator m = m_macros.begin (); m != m_macros.end (); ++m) {
@ -1861,30 +1875,42 @@ bool MacroCollection::has_autorun_early () const
return has_autorun_for (*this, true);
}
static void autorun_for (lym::MacroCollection &collection, bool early)
static void autorun_for (lym::MacroCollection &collection, bool early, std::set<std::string> *executed_already)
{
for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
autorun_for (*c->second, early);
autorun_for (*c->second, early, executed_already);
}
for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
if (c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) {
BEGIN_PROTECTED_SILENT
c->second->run ();
c->second->install_doc ();
END_PROTECTED_SILENT
if (!executed_already || executed_already->find (c->second->path ()) == executed_already->end ()) {
BEGIN_PROTECTED_SILENT
c->second->run ();
c->second->install_doc ();
END_PROTECTED_SILENT
if (executed_already) {
executed_already->insert (c->second->path ());
}
}
}
}
}
void MacroCollection::autorun ()
void MacroCollection::autorun (std::set<std::string> *already_executed)
{
autorun_for (*this, false);
autorun_for (*this, false, already_executed);
}
void MacroCollection::autorun_early ()
void MacroCollection::autorun_early (std::set<std::string> *already_executed)
{
autorun_for (*this, true);
autorun_for (*this, true, already_executed);
}
void MacroCollection::dump (int l)

View File

@ -845,6 +845,12 @@ public:
*/
void add_unspecific (lym::Macro *m);
/**
* @brief Empties the collection
* Note: only the unspecific on_changed event is generated.
*/
void clear ();
/**
* @brief Erases the given macro from the list
*
@ -995,7 +1001,7 @@ public:
/**
* @brief Runs all macros marked with auto-run
*/
void autorun ();
void autorun (std::set<std::string> *already_executed = 0);
/**
* @brief Returns true, if the collection has an early autorun macro
@ -1005,7 +1011,7 @@ public:
/**
* @brief Runs all macros marked with early auto-run
*/
void autorun_early ();
void autorun_early (std::set<std::string> *already_executed = 0);
/**
* @brief Redo the scan (will add new files or folders)
@ -1129,6 +1135,8 @@ private:
m_readonly = f;
}
void do_clear ();
// no copying
MacroCollection (const MacroCollection &d);
MacroCollection &operator= (const MacroCollection &d);