✨ can now create plugins from python.
parent
dc3c855ecf
commit
8bdf764cb3
16
meson.build
16
meson.build
|
@ -7,8 +7,14 @@ project('tiwiq',
|
||||||
'cpp_std=c++17',
|
'cpp_std=c++17',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
py3 = import('python')
|
||||||
|
py3_inst = py3.find_installation('python3')
|
||||||
|
py3_dep = py3_inst.dependency(embed: true)
|
||||||
|
|
||||||
twq_lib = static_library('tiwiq',
|
twq_lib = static_library('tiwiq',
|
||||||
sources: [
|
sources: [
|
||||||
|
'src/Global.cpp',
|
||||||
|
|
||||||
'src/core/Binding.cpp',
|
'src/core/Binding.cpp',
|
||||||
'src/core/Command.cpp',
|
'src/core/Command.cpp',
|
||||||
'src/core/Context.cpp',
|
'src/core/Context.cpp',
|
||||||
|
@ -33,9 +39,13 @@ twq_lib = static_library('tiwiq',
|
||||||
'src/term/Controller.cpp',
|
'src/term/Controller.cpp',
|
||||||
'src/term/View.cpp',
|
'src/term/View.cpp',
|
||||||
'src/term/Term.cpp',
|
'src/term/Term.cpp',
|
||||||
|
|
||||||
|
'src/script/Scripts.cpp',
|
||||||
|
'src/script/Loader.cpp',
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
dependency('ncursesw')
|
py3_dep,
|
||||||
|
dependency('ncursesw'),
|
||||||
])
|
])
|
||||||
|
|
||||||
twq_dep = declare_dependency(
|
twq_dep = declare_dependency(
|
||||||
|
@ -48,7 +58,8 @@ executable('twq',
|
||||||
'src/main.cpp'
|
'src/main.cpp'
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
twq_dep
|
twq_dep,
|
||||||
|
py3_dep,
|
||||||
],
|
],
|
||||||
install: true)
|
install: true)
|
||||||
|
|
||||||
|
@ -60,5 +71,6 @@ executable('twq-tests',
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
twq_dep,
|
twq_dep,
|
||||||
|
py3_dep,
|
||||||
dependency('catch2')
|
dependency('catch2')
|
||||||
])
|
])
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "Global.hpp"
|
||||||
|
|
||||||
|
namespace twq
|
||||||
|
{
|
||||||
|
std::shared_ptr<core::Tiwiq> Global::tiwiq = nullptr;
|
||||||
|
std::shared_ptr<term::Term> Global::term = nullptr;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef twq_GLOBAL_HPP
|
||||||
|
#define twq_GLOBAL_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "core/Tiwiq.hpp"
|
||||||
|
#include "term/Term.hpp"
|
||||||
|
|
||||||
|
namespace twq
|
||||||
|
{
|
||||||
|
class Global
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<core::Tiwiq> tiwiq;
|
||||||
|
static std::shared_ptr<term::Term> term;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -11,6 +11,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#define GEN_ENUM(X) X
|
#define GEN_ENUM(X) X
|
||||||
#define GEN_STRING(X) #X
|
#define GEN_STRING(X) #X
|
||||||
|
|
|
@ -26,11 +26,10 @@ namespace twq
|
||||||
|
|
||||||
bool equals(Color const& rhs) const;
|
bool equals(Color const& rhs) const;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
int m_red;
|
int m_red;
|
||||||
int m_green;
|
int m_green;
|
||||||
int m_blue;
|
int m_blue;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace twq
|
||||||
std::weak_ptr<UI> ui() { return m_ui; }
|
std::weak_ptr<UI> ui() { return m_ui; }
|
||||||
|
|
||||||
std::weak_ptr<Executor> executor();
|
std::weak_ptr<Executor> executor();
|
||||||
private:
|
protected:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::shared_ptr<Executor> m_executor;
|
std::shared_ptr<Executor> m_executor;
|
||||||
std::shared_ptr<UI> m_ui =
|
std::shared_ptr<UI> m_ui =
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "Tiwiq.hpp"
|
#include "Tiwiq.hpp"
|
||||||
#include "Event.hpp"
|
#include "Event.hpp"
|
||||||
#include "Executor.hpp"
|
#include "Executor.hpp"
|
||||||
|
#include "src/commons.hpp"
|
||||||
|
|
||||||
namespace twq
|
namespace twq
|
||||||
{
|
{
|
||||||
|
@ -29,14 +30,25 @@ namespace twq
|
||||||
m_plugins.push_back(plugin);
|
m_plugins.push_back(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tiwiq::rem_plugin(std::shared_ptr<Plugin> plugin)
|
||||||
|
{
|
||||||
|
auto itr = std::remove_if(std::begin(m_plugins),
|
||||||
|
std::end(m_plugins),
|
||||||
|
[&plugin](auto const& p){
|
||||||
|
return p->name() == plugin->name();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_plugins.erase(itr, std::end(m_plugins));
|
||||||
|
}
|
||||||
|
|
||||||
void Tiwiq::update(Event& event) /*override*/
|
void Tiwiq::update(Event& event) /*override*/
|
||||||
{
|
{
|
||||||
if (event.type == EVENT_KEY)
|
if (event.type == EVENT_KEY)
|
||||||
{
|
{
|
||||||
if (!m_plugins.empty())
|
for (auto plugin: m_plugins)
|
||||||
{
|
{
|
||||||
Context ctx { *this };
|
Context ctx { *this };
|
||||||
m_plugins.back()->executor().lock()->update(ctx, *event.key);
|
plugin->executor().lock()->update(ctx, *event.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace twq
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void add_plugin(std::shared_ptr<Plugin> plugin);
|
void add_plugin(std::shared_ptr<Plugin> plugin);
|
||||||
|
void rem_plugin(std::shared_ptr<Plugin> plugin);
|
||||||
|
|
||||||
|
|
||||||
void update(Event& event) override;
|
void update(Event& event) override;
|
||||||
|
|
||||||
|
|
31
src/main.cpp
31
src/main.cpp
|
@ -1,27 +1,48 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "Global.hpp"
|
||||||
#include "core/Tiwiq.hpp"
|
#include "core/Tiwiq.hpp"
|
||||||
#include "term/Term.hpp"
|
#include "term/Term.hpp"
|
||||||
#include "plugins/CorePlugin.hpp"
|
#include "plugins/CorePlugin.hpp"
|
||||||
|
#include "script/Decl.hpp"
|
||||||
|
#include "script/Scripts.hpp"
|
||||||
|
#include "script/Loader.hpp"
|
||||||
|
|
||||||
int main(int, char**)
|
int main(int, char**)
|
||||||
{
|
{
|
||||||
auto tiwiq = std::make_shared<twq::core::Tiwiq>();
|
pybind11::scoped_interpreter m_scope;
|
||||||
auto term = std::make_shared<twq::term::Term>();
|
|
||||||
|
|
||||||
|
auto tiwiq = std::make_shared<twq::core::Tiwiq>();
|
||||||
|
twq::Global::tiwiq = tiwiq;
|
||||||
|
auto term = std::make_shared<twq::term::Term>();
|
||||||
|
twq::Global::term = term;
|
||||||
term->controller().lock()->add_observer(tiwiq);
|
term->controller().lock()->add_observer(tiwiq);
|
||||||
|
|
||||||
// Build and add plugins
|
// Build and add plugins
|
||||||
// ---------------------
|
// ---------------------
|
||||||
auto core_plugin = std::make_shared<twq::plugins::CorePlugin>();
|
auto core_plugin = std::make_shared<twq::plugins::CorePlugin>();
|
||||||
core_plugin->ui().lock()->add_observer(term->view().lock());
|
|
||||||
core_plugin->ui().lock()->resize(term->view().lock()->dim());
|
|
||||||
|
|
||||||
|
term->add_plugin(core_plugin);
|
||||||
tiwiq->add_plugin(core_plugin);
|
tiwiq->add_plugin(core_plugin);
|
||||||
|
|
||||||
|
// Load scripts
|
||||||
|
// ------------
|
||||||
|
twq::script::Loader loader;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loader.load();
|
||||||
|
}
|
||||||
|
catch(std::exception const& err)
|
||||||
|
{
|
||||||
|
endwin();
|
||||||
|
std::cerr << err.what() << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Start TiwiQ
|
// Start TiwiQ
|
||||||
// -----------
|
// -----------
|
||||||
|
|
||||||
tiwiq->start();
|
tiwiq->start();
|
||||||
bool a = true;
|
|
||||||
|
|
||||||
while (tiwiq->is_running())
|
while (tiwiq->is_running())
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef twq_script_DECL_HPP
|
||||||
|
#define twq_script_DECL_HPP
|
||||||
|
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
#include "Scripts.hpp"
|
||||||
|
|
||||||
|
namespace twq
|
||||||
|
{
|
||||||
|
namespace script
|
||||||
|
{
|
||||||
|
PYBIND11_EMBEDDED_MODULE(tiwiq, m)
|
||||||
|
{
|
||||||
|
py::class_<ScriptPlugin,
|
||||||
|
std::shared_ptr<ScriptPlugin>>(m, "Plugin")
|
||||||
|
.def(py::init<std::string const&>())
|
||||||
|
.def("bind", &ScriptPlugin::bind)
|
||||||
|
.def("write_char", &ScriptPlugin::write_char);
|
||||||
|
|
||||||
|
py::class_<ScriptColor>(m, "Color")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::init<int, int, int>());
|
||||||
|
|
||||||
|
m.def("mount", &mount);
|
||||||
|
m.def("umount", &umount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include <pybind11/eval.h>
|
||||||
|
|
||||||
|
#include "Loader.hpp"
|
||||||
|
|
||||||
|
namespace twq
|
||||||
|
{
|
||||||
|
namespace script
|
||||||
|
{
|
||||||
|
/*explicit*/ Loader::Loader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Loader::~Loader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loader::load()
|
||||||
|
{
|
||||||
|
auto dir = get_twq_dir();
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(dir))
|
||||||
|
{
|
||||||
|
std::filesystem::create_directory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto autodir = dir / "autoloads";
|
||||||
|
|
||||||
|
if (std::filesystem::exists(autodir))
|
||||||
|
{
|
||||||
|
for (auto entry: std::filesystem::directory_iterator(autodir))
|
||||||
|
{
|
||||||
|
if (entry.path().has_extension()
|
||||||
|
&& entry.path().extension() == ".py")
|
||||||
|
{
|
||||||
|
load_py(entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto init_file = dir / "init.py";
|
||||||
|
|
||||||
|
if (std::filesystem::exists(init_file))
|
||||||
|
{
|
||||||
|
load_py(init_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path Loader::get_twq_dir()
|
||||||
|
{
|
||||||
|
auto home = std::filesystem::path(getenv("HOME"));
|
||||||
|
TWQ_ASSERT(std::filesystem::exists(home), "cannot find home directory");
|
||||||
|
|
||||||
|
return home / ".tiwiq.d";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loader::load_py(std::filesystem::path script_path)
|
||||||
|
{
|
||||||
|
pybind11::eval_file(script_path.string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef twq_script_LOADER_HPP
|
||||||
|
#define twq_script_LOADER_HPP
|
||||||
|
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
|
||||||
|
#include "../commons.hpp"
|
||||||
|
|
||||||
|
namespace twq
|
||||||
|
{
|
||||||
|
namespace script
|
||||||
|
{
|
||||||
|
class Loader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Loader();
|
||||||
|
virtual ~Loader();
|
||||||
|
|
||||||
|
void load();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::filesystem::path get_twq_dir();
|
||||||
|
void load_py(std::filesystem::path script_path);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include "Scripts.hpp"
|
||||||
|
|
||||||
|
namespace twq
|
||||||
|
{
|
||||||
|
namespace script
|
||||||
|
{
|
||||||
|
void mount(std::shared_ptr<ScriptPlugin> plugin)
|
||||||
|
{
|
||||||
|
Global::tiwiq->add_plugin(plugin);
|
||||||
|
Global::term->add_plugin(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void umount(std::shared_ptr<ScriptPlugin> plugin)
|
||||||
|
{
|
||||||
|
Global::tiwiq->rem_plugin(plugin);
|
||||||
|
Global::term->rem_plugin(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
#ifndef twq_script_SCRIPTS_HPP
|
||||||
|
#define twq_script_SCRIPTS_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/embed.h>
|
||||||
|
#include <pybind11/functional.h>
|
||||||
|
|
||||||
|
#include "../Global.hpp"
|
||||||
|
#include "../commons.hpp"
|
||||||
|
|
||||||
|
#include "../core/Executor.hpp"
|
||||||
|
#include "../core/Plugin.hpp"
|
||||||
|
#include "../core/Command.hpp"
|
||||||
|
#include "../core/Shortcut.hpp"
|
||||||
|
#include "../core/Binding.hpp"
|
||||||
|
|
||||||
|
#include "../core/Context.hpp"
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
namespace twq
|
||||||
|
{
|
||||||
|
namespace script
|
||||||
|
{
|
||||||
|
using command_t = std::function<void()>;
|
||||||
|
|
||||||
|
struct ScriptColor: public core::Color {
|
||||||
|
ScriptColor()
|
||||||
|
: core::Color()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptColor(int r, int g, int b)
|
||||||
|
: core::Color(r, g, b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScriptCommand: public core::Command {
|
||||||
|
command_t cmd;
|
||||||
|
|
||||||
|
ScriptCommand(command_t mycmd)
|
||||||
|
: cmd { mycmd }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(core::Context&) override
|
||||||
|
{
|
||||||
|
cmd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void undo(core::Context&) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScriptPlugin: public core::Plugin {
|
||||||
|
ScriptPlugin(std::string const& name)
|
||||||
|
: core::Plugin(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind(std::string const& shortcut_str, command_t cmd)
|
||||||
|
{
|
||||||
|
auto command = std::make_shared<ScriptCommand>(cmd);
|
||||||
|
std::wstring wstr(std::begin(shortcut_str),
|
||||||
|
std::end(shortcut_str));
|
||||||
|
auto shortcut = std::make_shared<core::Shortcut>(wstr);
|
||||||
|
core::Binding binding {shortcut, command};
|
||||||
|
m_executor->register_binding(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_char(int row, int col,
|
||||||
|
ScriptColor bg,
|
||||||
|
ScriptColor fg,
|
||||||
|
wchar_t text)
|
||||||
|
{
|
||||||
|
m_ui->write(core::Pixel {bg, fg, text}, core::Coord {row, col});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mount and umount plugins
|
||||||
|
void mount(std::shared_ptr<ScriptPlugin> plugin);
|
||||||
|
void umount(std::shared_ptr<ScriptPlugin> plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,5 +23,15 @@ namespace twq
|
||||||
{
|
{
|
||||||
endwin();
|
endwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Term::add_plugin(std::shared_ptr<core::Plugin> plugin)
|
||||||
|
{
|
||||||
|
plugin->ui().lock()->add_observer(m_view);
|
||||||
|
plugin->ui().lock()->resize(m_view->dim());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Term::rem_plugin(std::shared_ptr<core::Plugin>)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
#include "../commons.hpp"
|
#include "../commons.hpp"
|
||||||
|
#include "../core/Plugin.hpp"
|
||||||
#include "Controller.hpp"
|
#include "Controller.hpp"
|
||||||
#include "View.hpp"
|
#include "View.hpp"
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@ namespace twq
|
||||||
std::weak_ptr<Controller> controller() { return m_controller; }
|
std::weak_ptr<Controller> controller() { return m_controller; }
|
||||||
std::weak_ptr<View> view() { return m_view; }
|
std::weak_ptr<View> view() { return m_view; }
|
||||||
|
|
||||||
|
void add_plugin(std::shared_ptr<core::Plugin> plugin);
|
||||||
|
void rem_plugin(std::shared_ptr<core::Plugin> plugin);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Controller> m_controller =
|
std::shared_ptr<Controller> m_controller =
|
||||||
std::make_shared<Controller>();
|
std::make_shared<Controller>();
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace twq
|
||||||
});
|
});
|
||||||
|
|
||||||
attron(COLOR_PAIR(pair));
|
attron(COLOR_PAIR(pair));
|
||||||
mvprintw(j, i, "%lc", event.draw->pixel.text);
|
mvprintw(i, j, "%lc", event.draw->pixel.text);
|
||||||
attroff(COLOR_PAIR(pair));
|
attroff(COLOR_PAIR(pair));
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|
Loading…
Reference in New Issue