script" context menu item.tags/v1.1.1
@@ -1,6 +1,3 @@ | |||||
[submodule "fswatch"] | |||||
path = fswatch | |||||
url = https://github.com/emcrisostomo/fswatch.git | |||||
[submodule "QuickJS"] | [submodule "QuickJS"] | ||||
path = QuickJS | path = QuickJS | ||||
url = https://github.com/JerrySievert/QuickJS.git | url = https://github.com/JerrySievert/QuickJS.git |
@@ -13,22 +13,18 @@ DISTRIBUTABLES += $(wildcard LICENSE*) | |||||
include $(RACK_DIR)/arch.mk | include $(RACK_DIR)/arch.mk | ||||
# fswatch | |||||
fswatch := dep/lib/libfswatch.a | |||||
DEPS += $(fswatch) | |||||
OBJECTS += $(fswatch) | |||||
ifdef ARCH_WIN | |||||
LDFLAGS += -lintl | |||||
FSWATCH_CONFIGURE_FLAGS += CFLAGS="-DHAVE_WINDOWS" CXXFLAGS="-DHAVE_WINDOWS" | |||||
endif | |||||
$(fswatch): | |||||
ifdef ARCH_WIN | |||||
cd fswatch && MINGWPREFIX=/mingw64 ../fswatch_mingw_patch.sh | |||||
endif | |||||
cd fswatch && ./autogen.sh | |||||
cd fswatch && $(CONFIGURE) $(FSWATCH_CONFIGURE_FLAGS) --enable-shared=no | |||||
cd fswatch && $(MAKE) | |||||
cd fswatch && $(MAKE) install | |||||
# Entropia File System Watcher | |||||
efsw := dep/lib/libefsw-static-release.a | |||||
DEPS += $(efsw) | |||||
OBJECTS += $(efsw) | |||||
$(efsw): | |||||
cd dep && $(WGET) "https://bitbucket.org/SpartanJ/efsw/get/e6afbec564e2.zip" | |||||
cd dep && $(SHA256) e6afbec564e2.zip 8589dbedac7434f1863637af696354a9f1fcc28c6397c37b492a797ae62976be | |||||
cd dep && $(UNZIP) e6afbec564e2.zip | |||||
cd dep/SpartanJ-efsw-e6afbec564e2 && premake4 gmake | |||||
cd dep/SpartanJ-efsw-e6afbec564e2 && $(MAKE) -C make/windows config=release efsw-static-lib | |||||
cd dep/SpartanJ-efsw-e6afbec564e2 && cp lib/libefsw-static-release.a $(DEP_PATH)/lib/ | |||||
cd dep/SpartanJ-efsw-e6afbec564e2 && cp -R include/efsw $(DEP_PATH)/include/ | |||||
# QuickJS | # QuickJS | ||||
quickjs := dep/lib/quickjs/libquickjs.a | quickjs := dep/lib/quickjs/libquickjs.a | ||||
@@ -89,6 +89,13 @@ function process(block) { | |||||
} | } | ||||
``` | ``` | ||||
## Build dependencies | |||||
### Windows | |||||
``` | |||||
pacman -S mingw-w64-x86_64-premake | |||||
``` | |||||
## Adding a script engine | ## Adding a script engine | ||||
- Add your scripting language library to the build system so it builds with `make dep`, following the Duktape example in the `Makefile`. | - Add your scripting language library to the build system so it builds with `make dep`, following the Duktape example in the `Makefile`. | ||||
@@ -1 +0,0 @@ | |||||
Subproject commit d5d2ea84da1f0b0da23921891965894a86c72c27 |
@@ -1,110 +0,0 @@ | |||||
#!/bin/sh | |||||
# fix missing S_ISLNK in libfswatch/src/libfswatch/c++/poll_monitor.cpp | |||||
patch -ulbf libfswatch/src/libfswatch/c++/poll_monitor.cpp << EOF | |||||
@@ -131,2 +131,3 @@ | |||||
+#ifndef _WIN32 | |||||
if (follow_symlinks && S_ISLNK(fd_stat.st_mode)) | |||||
@@ -139,2 +140,3 @@ | |||||
} | |||||
+#endif | |||||
EOF | |||||
# fix missing realpath/lstat in libfswatch/src/libfswatch/c++/path_utils.cpp | |||||
patch -ulbf libfswatch/src/libfswatch/c++/path_utils.cpp << EOF | |||||
@@ -59,2 +59,5 @@ | |||||
{ | |||||
+#ifdef _WIN32 | |||||
+ return false; | |||||
+#else | |||||
char *real_path = realpath(path.c_str(), nullptr); | |||||
@@ -66,2 +69,3 @@ | |||||
return ret; | |||||
+#endif | |||||
} | |||||
@@ -82,2 +86,6 @@ | |||||
{ | |||||
+#ifdef _WIN32 | |||||
+ fsw_logf_perror(_("Cannot lstat %s (not implemented on Windows)"), path.c_str()); | |||||
+ return false; | |||||
+#else | |||||
if (lstat(path.c_str(), &fd_stat) != 0) | |||||
@@ -90,2 +98,3 @@ | |||||
return true; | |||||
+#endif | |||||
} | |||||
EOF | |||||
# fix missing sigaction/realpath in fswatch/src/fswatch.cpp | |||||
patch -ulbf fswatch/src/fswatch.cpp << EOF | |||||
@@ -36,2 +36,5 @@ | |||||
#include "libfswatch/c++/libfswatch_exception.hpp" | |||||
+#ifdef _WIN32 | |||||
+#define realpath(N,R) _fullpath((R),(N),_MAX_PATH) | |||||
+#endif | |||||
@@ -297,2 +300,3 @@ | |||||
{ | |||||
+#ifndef _WIN32 | |||||
struct sigaction action; | |||||
@@ -328,2 +332,3 @@ | |||||
} | |||||
+#endif | |||||
} | |||||
EOF | |||||
# fix libfswatch/src/libfswatch/c++/windows/win_paths.cpp | |||||
patch -ulbf libfswatch/src/libfswatch/c++/windows/win_paths.cpp << EOF | |||||
@@ -16,3 +16,7 @@ | |||||
#include "win_paths.hpp" | |||||
+#ifdef __CYGWIN__ | |||||
#include <sys/cygwin.h> | |||||
+#else | |||||
+#include <windows.h> | |||||
+#endif | |||||
#include "../libfswatch_exception.hpp" | |||||
@@ -28,2 +32,3 @@ | |||||
{ | |||||
+#ifdef __CYGWIN__ | |||||
void * raw_path = cygwin_create_path(CCP_POSIX_TO_WIN_W, path.c_str()); | |||||
@@ -36,2 +41,11 @@ | |||||
return win_path; | |||||
+#else | |||||
+ int pathlen = (int)path.length() + 1; | |||||
+ int buflen = MultiByteToWideChar(CP_ACP, 0, path.c_str(), pathlen, 0, 0); | |||||
+ wchar_t* buf = new wchar_t[buflen]; | |||||
+ MultiByteToWideChar(CP_ACP, 0, path.c_str(), pathlen, buf, buflen); | |||||
+ std::wstring result(buf); | |||||
+ delete[] buf; | |||||
+ return result; | |||||
+#endif | |||||
} | |||||
@@ -40,2 +54,3 @@ | |||||
{ | |||||
+#ifdef __CYGWIN__ | |||||
void * raw_path = cygwin_create_path(CCP_WIN_W_TO_POSIX, path.c_str()); | |||||
@@ -48,2 +63,11 @@ | |||||
return posix_path; | |||||
+#else | |||||
+ int pathlen = (int)path.length() + 1; | |||||
+ int buflen = WideCharToMultiByte(CP_ACP, 0, path.c_str(), pathlen, 0, 0, 0, 0); | |||||
+ char* buf = new char[buflen]; | |||||
+ WideCharToMultiByte(CP_ACP, 0, path.c_str(), pathlen, buf, buflen, 0, 0); | |||||
+ std::string result(buf); | |||||
+ delete[] buf; | |||||
+ return result; | |||||
+#endif | |||||
} | |||||
EOF | |||||
# fix missing file | |||||
touch README.illumos | |||||
# remove detection of realpath/regcomp/select | |||||
mv libfswatch/configure.ac libfswatch/configure.ac.bak && | |||||
grep -v "realpath\|regcomp\|select" libfswatch/configure.ac.bak > libfswatch/configure.ac | |||||
# remove detection of realpath | |||||
mv configure.ac configure.ac.bak2 && | |||||
grep -v "realpath" configure.ac.bak2 > configure.ac | |||||
# remove detection of realpath | |||||
mv configure.ac configure.ac.bak3 && | |||||
grep -v "The select function cannot be found." configure.ac.bak3 > configure.ac | |||||
# fix for building windows_monitor | |||||
mv libfswatch/src/libfswatch/Makefile.am libfswatch/src/libfswatch/Makefile.am.bak && | |||||
sed -e "s/USE_CYGWIN/USE_WINDOWS/" libfswatch/src/libfswatch/Makefile.am.bak > libfswatch/src/libfswatch/Makefile.am |
@@ -6,7 +6,7 @@ | |||||
#include <mutex> | #include <mutex> | ||||
#include <thread> | #include <thread> | ||||
#include "ScriptEngine.hpp" | #include "ScriptEngine.hpp" | ||||
#include <libfswatch/c/libfswatch.h> | |||||
#include <efsw/efsw.h> | |||||
using namespace rack; | using namespace rack; | ||||
@@ -44,8 +44,7 @@ struct Prototype : Module { | |||||
ScriptEngine::ProcessBlock* block; | ScriptEngine::ProcessBlock* block; | ||||
int bufferIndex = 0; | int bufferIndex = 0; | ||||
FSW_SESSION* fsw = NULL; | |||||
std::thread watchThread; | |||||
efsw_watcher efsw = NULL; | |||||
Prototype() { | Prototype() { | ||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
@@ -128,11 +127,9 @@ struct Prototype : Module { | |||||
void setPath(std::string path) { | void setPath(std::string path) { | ||||
// Cleanup | // Cleanup | ||||
if (fsw) { | |||||
fsw_stop_monitor(fsw); | |||||
fsw_destroy_session(fsw); | |||||
watchThread.join(); | |||||
fsw = NULL; | |||||
if (efsw) { | |||||
efsw_release(efsw); | |||||
efsw = NULL; | |||||
} | } | ||||
this->path = ""; | this->path = ""; | ||||
setScript(""); | setScript(""); | ||||
@@ -147,22 +144,10 @@ struct Prototype : Module { | |||||
return; | return; | ||||
// Watch file | // Watch file | ||||
FSW_STATUS err = fsw_init_library(); | |||||
if (err == FSW_OK) { | |||||
#if defined ARCH_LIN | |||||
fsw_monitor_type type = inotify_monitor_type; | |||||
#elif defined ARCH_MAC | |||||
fsw_monitor_type type = fsevents_monitor_type; | |||||
#elif defined ARCH_WIN | |||||
fsw_monitor_type type = windows_monitor_type; | |||||
#endif | |||||
fsw = fsw_init_session(type); | |||||
fsw_add_path(fsw, this->path.c_str()); | |||||
fsw_set_callback(fsw, watchCallback, this); | |||||
fsw_set_allow_overflow(fsw, false); | |||||
fsw_set_latency(fsw, 0.5); | |||||
watchThread = std::thread(watchRun, fsw); | |||||
} | |||||
std::string dir = string::directory(path); | |||||
efsw = efsw_create(false); | |||||
efsw_addwatch(efsw, dir.c_str(), watchCallback, false, this); | |||||
efsw_watch(efsw); | |||||
} | } | ||||
void loadPath() { | void loadPath() { | ||||
@@ -231,23 +216,13 @@ struct Prototype : Module { | |||||
this->engineName = scriptEngine->getEngineName(); | this->engineName = scriptEngine->getEngineName(); | ||||
} | } | ||||
static void watchRun(FSW_SESSION* fsw) { | |||||
fsw_start_monitor(fsw); | |||||
} | |||||
static void watchCallback(fsw_cevent const* const events, const unsigned int event_num, void* data) { | |||||
Prototype* that = (Prototype*) data; | |||||
if (event_num < 1) | |||||
return; | |||||
// Look for flags | |||||
for (unsigned i = 0; i < event_num; i++) { | |||||
for (unsigned j = 0; j < events[i].flags_num; j++) { | |||||
fsw_event_flag flag = events[i].flags[j]; | |||||
if (flag == Created || flag == Updated) { | |||||
that->loadPath(); | |||||
return; | |||||
} | |||||
static void watchCallback(efsw_watcher watcher, efsw_watchid watchid, const char* dir, const char* filename, enum efsw_action action, const char* old_filename, void* param) { | |||||
Prototype* that = (Prototype*) param; | |||||
if (action == EFSW_ADD || action == EFSW_DELETE || action == EFSW_MODIFIED || action == EFSW_MOVED) { | |||||
// Check filename | |||||
std::string pathFilename = string::filename(that->path); | |||||
if (pathFilename == filename) { | |||||
that->loadPath(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -291,6 +266,10 @@ struct Prototype : Module { | |||||
setPath(path); | setPath(path); | ||||
} | } | ||||
void reloadScript() { | |||||
loadPath(); | |||||
} | |||||
void saveScriptDialog() { | void saveScriptDialog() { | ||||
if (script == "") | if (script == "") | ||||
return; | return; | ||||
@@ -403,6 +382,14 @@ struct LoadScriptItem : MenuItem { | |||||
}; | }; | ||||
struct ReloadScriptItem : MenuItem { | |||||
Prototype* module; | |||||
void onAction(const event::Action& e) override { | |||||
module->reloadScript(); | |||||
} | |||||
}; | |||||
struct SaveScriptItem : MenuItem { | struct SaveScriptItem : MenuItem { | ||||
Prototype* module; | Prototype* module; | ||||
void onAction(const event::Action& e) override { | void onAction(const event::Action& e) override { | ||||
@@ -475,6 +462,10 @@ struct PrototypeWidget : ModuleWidget { | |||||
loadScriptItem->module = module; | loadScriptItem->module = module; | ||||
menu->addChild(loadScriptItem); | menu->addChild(loadScriptItem); | ||||
ReloadScriptItem* reloadScriptItem = createMenuItem<ReloadScriptItem>("Reload script"); | |||||
reloadScriptItem->module = module; | |||||
menu->addChild(reloadScriptItem); | |||||
SaveScriptItem* saveScriptItem = createMenuItem<SaveScriptItem>("Save script as"); | SaveScriptItem* saveScriptItem = createMenuItem<SaveScriptItem>("Save script as"); | ||||
saveScriptItem->module = module; | saveScriptItem->module = module; | ||||
menu->addChild(saveScriptItem); | menu->addChild(saveScriptItem); | ||||