mirror of
https://github.com/bjornbytes/lovr.git
synced 2024-07-05 13:53:38 +00:00
Live reloading;
Use -w or --watch to watch source directory for changes and call lovr.filechanged when a file is changed. By default lovr.filechanged will restart lovr. It's powered by lovr.filesystem.watch/lovr.filesystem.unwatch functions, but these are currently hardcoded to only watch the whole source folder. Currently there is a bug where it only restarts on the first change, this is seemingly a problem with dmon.
This commit is contained in:
parent
52488725b8
commit
9301c73f14
|
@ -421,6 +421,7 @@ if(LOVR_ENABLE_FILESYSTEM)
|
|||
src/modules/filesystem/filesystem.c
|
||||
src/api/l_filesystem.c
|
||||
src/api/l_filesystem_file.c
|
||||
src/lib/dmon/dmon.c
|
||||
src/lib/miniz/miniz_tinfl.c
|
||||
)
|
||||
else()
|
||||
|
|
|
@ -393,6 +393,7 @@ src += 'src/lib/miniz/*.c'
|
|||
src += (config.modules.audio or config.modules.data) and 'src/lib/miniaudio/*.c' or nil
|
||||
src += config.modules.data and 'src/lib/jsmn/*.c' or nil
|
||||
src += config.modules.data and 'src/lib/minimp3/*.c' or nil
|
||||
src += config.modules.filesystem and 'src/lib/dmon/*.c' or nil
|
||||
src += config.modules.math and 'src/lib/noise/*.c' or nil
|
||||
src += config.modules.thread and 'src/core/job.c' or nil
|
||||
|
||||
|
|
|
@ -282,6 +282,10 @@ function lovr.threaderror(thread, err)
|
|||
error('Thread error\n\n' .. err, 0)
|
||||
end
|
||||
|
||||
function lovr.filechanged(path, action, oldpath)
|
||||
lovr.event.restart()
|
||||
end
|
||||
|
||||
function lovr.log(message, level, tag)
|
||||
message = message:gsub('\n$', '')
|
||||
print(message)
|
||||
|
|
|
@ -3,7 +3,8 @@ function lovr.arg(arg)
|
|||
_help = { short = '-h', long = '--help', help = 'Show help and exit' },
|
||||
_version = { short = '-v', long = '--version', help = 'Show version and exit' },
|
||||
console = { long = '--console', help = 'Attach Windows console' },
|
||||
debug = { long = '--debug', help = 'Enable debugging checks and logging' }
|
||||
debug = { long = '--debug', help = 'Enable debugging checks and logging' },
|
||||
watch = { short = '-w', long = '--watch', help = 'Watch files and restart on change' }
|
||||
}
|
||||
|
||||
local shift
|
||||
|
@ -68,5 +69,9 @@ function lovr.arg(arg)
|
|||
if arg.debug then
|
||||
conf.graphics.debug = true
|
||||
end
|
||||
|
||||
if arg.watch then
|
||||
lovr.filesystem.watch()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,6 +38,7 @@ extern StringEntry lovrDrawMode[];
|
|||
extern StringEntry lovrDrawStyle[];
|
||||
extern StringEntry lovrEffect[];
|
||||
extern StringEntry lovrEventType[];
|
||||
extern StringEntry lovrFileAction[];
|
||||
extern StringEntry lovrFilterMode[];
|
||||
extern StringEntry lovrHeadsetDriver[];
|
||||
extern StringEntry lovrHorizontalAlign[];
|
||||
|
|
|
@ -22,6 +22,7 @@ StringEntry lovrEventType[] = {
|
|||
#ifndef LOVR_DISABLE_THREAD
|
||||
[EVENT_THREAD_ERROR] = ENTRY("threaderror"),
|
||||
#endif
|
||||
[EVENT_FILECHANGED] = ENTRY("filechanged"),
|
||||
[EVENT_PERMISSION] = ENTRY("permission"),
|
||||
{ 0 }
|
||||
};
|
||||
|
@ -207,6 +208,14 @@ static int nextEvent(lua_State* L) {
|
|||
return 3;
|
||||
#endif
|
||||
|
||||
case EVENT_FILECHANGED:
|
||||
lua_pushstring(L, event.data.file.path);
|
||||
luax_pushenum(L, FileAction, event.data.file.action);
|
||||
lua_pushstring(L, event.data.file.oldpath);
|
||||
free(event.data.file.path);
|
||||
free(event.data.file.oldpath);
|
||||
return 4;
|
||||
|
||||
case EVENT_PERMISSION:
|
||||
luax_pushenum(L, Permission, event.data.permission.permission);
|
||||
lua_pushboolean(L, event.data.permission.granted);
|
||||
|
|
|
@ -5,6 +5,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
StringEntry lovrFileAction[] = {
|
||||
[FILE_CREATE] = ENTRY("create"),
|
||||
[FILE_DELETE] = ENTRY("delete"),
|
||||
[FILE_MODIFY] = ENTRY("modify"),
|
||||
[FILE_RENAME] = ENTRY("rename"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrOpenMode[] = {
|
||||
[OPEN_READ] = ENTRY("r"),
|
||||
[OPEN_WRITE] = ENTRY("w"),
|
||||
|
@ -349,6 +357,16 @@ static int l_lovrFilesystemUnmount(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemUnwatch(lua_State* L) {
|
||||
lovrFilesystemUnwatch();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemWatch(lua_State* L) {
|
||||
lovrFilesystemWatch();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemWrite(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
size_t size;
|
||||
|
@ -411,6 +429,8 @@ static const luaL_Reg lovrFilesystem[] = {
|
|||
{ "setRequirePath", l_lovrFilesystemSetRequirePath },
|
||||
{ "setSource", l_lovrFilesystemSetSource },
|
||||
{ "unmount", l_lovrFilesystemUnmount },
|
||||
{ "unwatch", l_lovrFilesystemUnwatch },
|
||||
{ "watch", l_lovrFilesystemWatch },
|
||||
{ "write", l_lovrFilesystemWrite },
|
||||
{ "newFile", l_lovrFilesystemNewFile },
|
||||
{ NULL, NULL }
|
||||
|
|
2
src/lib/dmon/dmon.c
Normal file
2
src/lib/dmon/dmon.c
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define DMON_IMPL
|
||||
#include "dmon.h"
|
1748
src/lib/dmon/dmon.h
Normal file
1748
src/lib/dmon/dmon.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -51,13 +51,26 @@ void lovrEventPush(Event event) {
|
|||
if (event.type == EVENT_THREAD_ERROR) {
|
||||
lovrRetain(event.data.thread.thread);
|
||||
size_t length = strlen(event.data.thread.error);
|
||||
char* copy = lovrMalloc(length + 1);
|
||||
memcpy(copy, event.data.thread.error, length);
|
||||
copy[length] = '\0';
|
||||
char* copy = malloc(length + 1);
|
||||
memcpy(copy, event.data.thread.error, length + 1);
|
||||
event.data.thread.error = copy;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (event.type == EVENT_FILECHANGED) {
|
||||
size_t length = strlen(event.data.file.path);
|
||||
char* copy = malloc(length + 1);
|
||||
memcpy(copy, event.data.file.path, length + 1);
|
||||
event.data.file.path = copy;
|
||||
|
||||
if (event.data.file.oldpath) {
|
||||
length = strlen(event.data.file.oldpath);
|
||||
copy = malloc(length + 1);
|
||||
memcpy(copy, event.data.file.oldpath, length + 1);
|
||||
event.data.file.oldpath = copy;
|
||||
}
|
||||
}
|
||||
|
||||
arr_push(&state.events, event);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ typedef enum {
|
|||
#ifndef LOVR_DISABLE_THREAD
|
||||
EVENT_THREAD_ERROR,
|
||||
#endif
|
||||
EVENT_FILECHANGED,
|
||||
EVENT_PERMISSION,
|
||||
EVENT_CUSTOM
|
||||
} EventType;
|
||||
|
@ -115,16 +116,22 @@ typedef struct {
|
|||
} ThreadEvent;
|
||||
|
||||
typedef struct {
|
||||
char name[MAX_EVENT_NAME_LENGTH];
|
||||
Variant data[4];
|
||||
uint32_t count;
|
||||
} CustomEvent;
|
||||
char* path;
|
||||
char* oldpath;
|
||||
int action;
|
||||
} FileEvent;
|
||||
|
||||
typedef struct {
|
||||
uint32_t permission;
|
||||
bool granted;
|
||||
} PermissionEvent;
|
||||
|
||||
typedef struct {
|
||||
char name[MAX_EVENT_NAME_LENGTH];
|
||||
Variant data[4];
|
||||
uint32_t count;
|
||||
} CustomEvent;
|
||||
|
||||
typedef union {
|
||||
QuitEvent quit;
|
||||
BoolEvent boolean;
|
||||
|
@ -134,8 +141,9 @@ typedef union {
|
|||
MouseEvent mouse;
|
||||
MouseWheelEvent wheel;
|
||||
ThreadEvent thread;
|
||||
CustomEvent custom;
|
||||
FileEvent file;
|
||||
PermissionEvent permission;
|
||||
CustomEvent custom;
|
||||
} EventData;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "filesystem/filesystem.h"
|
||||
#include "event/event.h"
|
||||
#include "core/fs.h"
|
||||
#include "core/os.h"
|
||||
#include "util.h"
|
||||
#include "lib/dmon/dmon.h"
|
||||
#include "lib/miniz/miniz_tinfl.h"
|
||||
#include <stdatomic.h>
|
||||
#include <string.h>
|
||||
|
@ -75,6 +77,8 @@ struct File {
|
|||
|
||||
static struct {
|
||||
uint32_t ref;
|
||||
bool watching;
|
||||
dmon_watch_id watchId;
|
||||
Archive* archives;
|
||||
size_t savePathLength;
|
||||
char savePath[1024];
|
||||
|
@ -175,6 +179,7 @@ void lovrFilesystemDestroy(void) {
|
|||
lovrRelease(archive, lovrArchiveDestroy);
|
||||
archive = next;
|
||||
}
|
||||
lovrFilesystemUnwatch();
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
|
@ -190,6 +195,41 @@ const char* lovrFilesystemGetSource(void) {
|
|||
return state.source[0] ? state.source : NULL;
|
||||
}
|
||||
|
||||
static void onFileEvent(dmon_watch_id id, dmon_action action, const char* dir, const char* path, const char* oldpath, void* ctx) {
|
||||
static const FileAction map[] = {
|
||||
[DMON_ACTION_CREATE] = FILE_CREATE,
|
||||
[DMON_ACTION_DELETE] = FILE_DELETE,
|
||||
[DMON_ACTION_MODIFY] = FILE_MODIFY,
|
||||
[DMON_ACTION_MOVE] = FILE_RENAME
|
||||
};
|
||||
|
||||
lovrEventPush((Event) {
|
||||
.type = EVENT_FILECHANGED,
|
||||
.data.file = {
|
||||
.path = (char*) path,
|
||||
.action = map[action],
|
||||
.oldpath = (char*) oldpath
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void lovrFilesystemWatch(void) {
|
||||
FileInfo info;
|
||||
if (!state.watching && fs_stat(state.source, &info) && info.type == FILE_DIRECTORY) {
|
||||
state.watching = true;
|
||||
dmon_init();
|
||||
state.watchId = dmon_watch(state.source, onFileEvent, DMON_WATCHFLAGS_RECURSIVE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrFilesystemUnwatch(void) {
|
||||
if (state.watching) {
|
||||
state.watching = false;
|
||||
dmon_unwatch(state.watchId);
|
||||
dmon_deinit();
|
||||
}
|
||||
}
|
||||
|
||||
bool lovrFilesystemIsFused(void) {
|
||||
char path[LOVR_PATH_MAX];
|
||||
const char* root;
|
||||
|
|
|
@ -9,11 +9,20 @@
|
|||
typedef struct Archive Archive;
|
||||
typedef struct File File;
|
||||
|
||||
typedef enum {
|
||||
FILE_CREATE,
|
||||
FILE_DELETE,
|
||||
FILE_MODIFY,
|
||||
FILE_RENAME
|
||||
} FileAction;
|
||||
|
||||
bool lovrFilesystemInit(void);
|
||||
void lovrFilesystemDestroy(void);
|
||||
void lovrFilesystemSetSource(const char* source);
|
||||
const char* lovrFilesystemGetSource(void);
|
||||
bool lovrFilesystemIsFused(void);
|
||||
void lovrFilesystemWatch(void);
|
||||
void lovrFilesystemUnwatch(void);
|
||||
bool lovrFilesystemMount(const char* path, const char* mountpoint, bool append, const char *root);
|
||||
bool lovrFilesystemUnmount(const char* path);
|
||||
const char* lovrFilesystemGetRealDirectory(const char* path);
|
||||
|
|
Loading…
Reference in a new issue