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"] | |||
path = QuickJS | |||
url = https://github.com/JerrySievert/QuickJS.git |
@@ -13,22 +13,18 @@ DISTRIBUTABLES += $(wildcard LICENSE*) | |||
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 := 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 | |||
- 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 <thread> | |||
#include "ScriptEngine.hpp" | |||
#include <libfswatch/c/libfswatch.h> | |||
#include <efsw/efsw.h> | |||
using namespace rack; | |||
@@ -44,8 +44,7 @@ struct Prototype : Module { | |||
ScriptEngine::ProcessBlock* block; | |||
int bufferIndex = 0; | |||
FSW_SESSION* fsw = NULL; | |||
std::thread watchThread; | |||
efsw_watcher efsw = NULL; | |||
Prototype() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
@@ -128,11 +127,9 @@ struct Prototype : Module { | |||
void setPath(std::string path) { | |||
// Cleanup | |||
if (fsw) { | |||
fsw_stop_monitor(fsw); | |||
fsw_destroy_session(fsw); | |||
watchThread.join(); | |||
fsw = NULL; | |||
if (efsw) { | |||
efsw_release(efsw); | |||
efsw = NULL; | |||
} | |||
this->path = ""; | |||
setScript(""); | |||
@@ -147,22 +144,10 @@ struct Prototype : Module { | |||
return; | |||
// 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() { | |||
@@ -231,23 +216,13 @@ struct Prototype : Module { | |||
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); | |||
} | |||
void reloadScript() { | |||
loadPath(); | |||
} | |||
void saveScriptDialog() { | |||
if (script == "") | |||
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 { | |||
Prototype* module; | |||
void onAction(const event::Action& e) override { | |||
@@ -475,6 +462,10 @@ struct PrototypeWidget : ModuleWidget { | |||
loadScriptItem->module = module; | |||
menu->addChild(loadScriptItem); | |||
ReloadScriptItem* reloadScriptItem = createMenuItem<ReloadScriptItem>("Reload script"); | |||
reloadScriptItem->module = module; | |||
menu->addChild(reloadScriptItem); | |||
SaveScriptItem* saveScriptItem = createMenuItem<SaveScriptItem>("Save script as"); | |||
saveScriptItem->module = module; | |||
menu->addChild(saveScriptItem); | |||