"\trun Compiles and runs an Onyx program, all at once.\n"
#endif
"\tcheck Checks syntax and types of an Onyx program.\n"
+ "\twatch Continuously rebuilds an Onyx program on file changes.\n"
"\tpackage Package manager\n";
// "\tdoc <input files>\n"
arg_parse_start = 2;
}
#endif
+ #ifdef _BH_LINUX
+ else if (!strcmp(argv[1], "watch")) {
+ options.action = ONYX_COMPILE_ACTION_WATCH;
+ arg_parse_start = 2;
+ }
+ #endif
else {
bh_printf("Unknown subcommand: '%s'\n", argv[1]);
bh_printf("Run \"onyx help\" for valid subcommands.\n");
static void print_subcommand_help(const char *subcommand) {
if (!strcmp(subcommand, "build")
|| !strcmp(subcommand, "run")
- || !strcmp(subcommand, "check")) {
+ || !strcmp(subcommand, "check")
+ || !strcmp(subcommand, "watch")) {
bh_printf(build_docstring, subcommand);
}
bh_managed_heap_free(&mh);
}
+#ifdef _BH_LINUX
+
+#include <signal.h>
+
+static bh_file_watch watches;
+
+static void onyx_watch_stop(int sig) {
+ bh_file_watch_stop(&watches);
+}
+
+static void onyx_watch(CompileOptions *compile_opts) {
+ signal(SIGINT, onyx_watch_stop);
+
+ b32 running_watch = 1;
+
+ do {
+ bh_printf("\e[2J\e[?25l\n");
+ bh_printf("\e[3;1H");
+
+ if (do_compilation(compile_opts) == ONYX_COMPILER_PROGRESS_SUCCESS) {
+ onyx_flush_module();
+ bh_printf("\e[92mNo errors.\n");
+ }
+
+ char time_buf[128] = {0};
+ time_t now = time(NULL);
+ strftime(time_buf, 128, "%X", localtime(&now));
+ bh_printf("\e[1;1H\e[30;104m [BUILT] %s \e[0m", time_buf);
+
+ i32 errors = bh_arr_length(context.errors.errors);
+ if (errors == 0) {
+ bh_printf("\e[30;102m [ERRORS] 0 \e[0m");
+ } else {
+ bh_printf("\e[30;101m [ERRORS] %d \e[0m", errors);
+ }
+
+ watches = bh_file_watch_new();
+
+ bh_arr_each(bh_file_contents, file, context.loaded_files) {
+ bh_file_watch_add(&watches, file->filename);
+ }
+
+ cleanup_compilation();
+
+ if (!bh_file_watch_wait(&watches)) {
+ running_watch = 0;
+ }
+
+ bh_file_watch_free(&watches);
+ } while(running_watch);
+
+
+ bh_printf("\e[2J\e[1;1H\e[?25h\n");
+}
+
+#endif
+
+
+
+
int main(int argc, char *argv[]) {
CompileOptions compile_opts = compile_opts_parse(bh_heap_allocator(), argc, argv);
}
break;
+ case ONYX_COMPILE_ACTION_WATCH:
+ onyx_watch(&compile_opts);
+ break;
+
#ifdef ENABLE_RUN_WITH_WASMER
case ONYX_COMPILE_ACTION_RUN:
compiler_progress = do_compilation(&compile_opts);
#include <unistd.h>
#include <dirent.h>
#include <pthread.h>
+ #include <sys/inotify.h>
+ #include <sys/select.h>
#endif
#include <stdlib.h>
-b32 bh_wait_for_changes_in_directories(u32 count, char ** paths);
+#ifdef _BH_LINUX
+ typedef struct bh_file_watch {
+ int inotify_fd;
+ int kill_pipe[2];
+
+ fd_set fds;
+ } bh_file_watch;
+#endif
+#ifdef _BH_WINDOWS
+ // TODO: Make these work on Windows
+ typedef u32 bh_file_watch;
+#endif
+
+bh_file_watch bh_file_watch_new();
+void bh_file_watch_free(bh_file_watch *w);
+void bh_file_watch_add(bh_file_watch *w, const char *filename);
+b32 bh_file_watch_wait(bh_file_watch *w);
+void bh_file_watch_stop(bh_file_watch *w);
+
#endif
#undef DIR_SEPARATOR
+#ifdef _BH_LINUX
+
+bh_file_watch bh_file_watch_new() {
+ // TODO: Proper error checking
+ bh_file_watch w;
+ assert(pipe(w.kill_pipe) != -1);
+
+ assert((w.inotify_fd = inotify_init()) != -1);
+
+ FD_ZERO(&w.fds);
+ FD_SET(w.inotify_fd, &w.fds);
+ FD_SET(w.kill_pipe[0], &w.fds);
+
+ return w;
+}
+
+void bh_file_watch_free(bh_file_watch *w) {
+ close(w->inotify_fd);
+ close(w->kill_pipe[0]);
+ close(w->kill_pipe[1]);
+}
+
+void bh_file_watch_add(bh_file_watch *w, const char *filename) {
+ inotify_add_watch(w->inotify_fd, filename, IN_MODIFY);
+}
+
+b32 bh_file_watch_wait(bh_file_watch *w) {
+ select(FD_SETSIZE, &w->fds, NULL, NULL, NULL);
+
+ if (FD_ISSET(w->kill_pipe[0], &w->fds)) {
+ char buf;
+ read(w->kill_pipe[0], &buf, sizeof(buf));
+ return 0;
+ }
+
+ FD_ZERO(&w->fds);
+ FD_SET(w->inotify_fd, &w->fds);
+ FD_SET(w->kill_pipe[0], &w->fds);
+
+ return 1;
+}
+
+void bh_file_watch_stop(bh_file_watch *w) {
+ char buf = 'a';
+ write(w->kill_pipe[1], &buf, 1);
+}
+
+#endif // ifdef _BH_LINUX
+
#endif // ifndef BH_NO_FILE