From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jan200101 <sentrycraft123@gmail.com>
Date: Wed, 13 Mar 2024 20:09:25 +0100
Subject: [PATCH] Add Minerva platform support

Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
 meson.build                         |  3 +-
 src/api/dirmonitor/inodewatcher.cpp | 75 +++++++++++++++++++++++++++++
 src/main.c                          |  7 ++-
 src/meson.build                     | 17 ++++---
 4 files changed, 93 insertions(+), 9 deletions(-)
 create mode 100644 src/api/dirmonitor/inodewatcher.cpp

diff --git a/meson.build b/meson.build
index 3f88be37..70627782 100644
--- a/meson.build
+++ b/meson.build
@@ -4,7 +4,8 @@ project('lite-xl',
     license : 'MIT',
     meson_version : '>= 0.56',
     default_options : [
-        'c_std=gnu11'
+        'c_std=gnu11',
+        'cpp_std=c++20'
     ]
 )
 
diff --git a/src/api/dirmonitor/inodewatcher.cpp b/src/api/dirmonitor/inodewatcher.cpp
new file mode 100644
index 00000000..e749f5bd
--- /dev/null
+++ b/src/api/dirmonitor/inodewatcher.cpp
@@ -0,0 +1,75 @@
+#include <AK/NumericLimits.h>
+#include <Kernel/API/InodeWatcherEvent.h>
+#include <Kernel/API/InodeWatcherFlags.h>
+#include <cstring>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+
+extern "C" {
+struct dirmonitor_internal* init_dirmonitor();
+void deinit_dirmonitor(struct dirmonitor_internal*);
+int get_changes_dirmonitor(struct dirmonitor_internal*, char*, int);
+int translate_changes_dirmonitor(struct dirmonitor_internal*, char*, int, int (*)(int, const char*, void*), void*);
+int add_dirmonitor(struct dirmonitor_internal*, const char*);
+void remove_dirmonitor(struct dirmonitor_internal*, int);
+int get_mode_dirmonitor();
+}
+
+struct dirmonitor_internal {
+  int fd;
+  // a pipe is used to wake the thread in case of exit
+  int sig[2];
+};
+
+
+struct dirmonitor_internal* init_dirmonitor() {
+  struct dirmonitor_internal* monitor = (struct dirmonitor_internal*)calloc(sizeof(struct dirmonitor_internal), 1);
+  monitor->fd = create_inode_watcher(0);
+  pipe(monitor->sig);
+  fcntl(monitor->sig[0], F_SETFD, FD_CLOEXEC);
+  fcntl(monitor->sig[1], F_SETFD, FD_CLOEXEC);
+  return monitor;
+}
+
+
+void deinit_dirmonitor(struct dirmonitor_internal* monitor) {
+  close(monitor->fd);
+  close(monitor->sig[0]);
+  close(monitor->sig[1]);
+}
+
+
+
+int get_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int length) {
+  struct pollfd fds[2] = { { .fd = monitor->fd, .events = POLLIN | POLLERR, .revents = 0 }, { .fd = monitor->sig[0], .events = POLLIN | POLLERR, .revents = 0 } };
+  poll(fds, 2, -1);
+  return read(monitor->fd, buffer, length);
+}
+
+
+int translate_changes_dirmonitor(struct dirmonitor_internal* monitor, char* buffer, int length, int (*change_callback)(int, const char*, void*), void* data) {
+  InodeWatcherEvent* event = (InodeWatcherEvent*)buffer;
+  change_callback(event->watch_descriptor, NULL, data);
+  return 0;
+}
+
+
+int add_dirmonitor(struct dirmonitor_internal* monitor, const char* path) {
+  return inode_watcher_add_watch(monitor->fd, path, strlen(path),
+      static_cast<unsigned>(
+        InodeWatcherEvent::Type::MetadataModified |
+        InodeWatcherEvent::Type::ContentModified |
+        InodeWatcherEvent::Type::Deleted |
+        InodeWatcherEvent::Type::ChildCreated |
+        InodeWatcherEvent::Type::ChildDeleted
+      ));
+}
+
+
+void remove_dirmonitor(struct dirmonitor_internal* monitor, int fd) {
+  inode_watcher_remove_watch(monitor->fd, fd);
+}
+
+int get_mode_dirmonitor() { return 2; }
diff --git a/src/main.c b/src/main.c
index dca3cbd1..e11fb7ae 100644
--- a/src/main.c
+++ b/src/main.c
@@ -9,7 +9,7 @@
 
 #ifdef _WIN32
   #include <windows.h>
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(__minerva__)
   #include <unistd.h>
 #elif defined(__APPLE__)
   #include <mach-o/dyld.h>
@@ -34,7 +34,7 @@ static void get_exe_filename(char *buf, int sz) {
   } else {
     buf[0] = '\0';
   }
-#elif __linux__
+#elif __linux__ || __minerva__
   char path[] = "/proc/self/exe";
   ssize_t len = readlink(path, buf, sz - 1);
   if (len > 0)
@@ -110,6 +110,9 @@ void set_macos_bundle_resources(lua_State *L);
     #define ARCH_PLATFORM "freebsd"
   #elif __APPLE__
     #define ARCH_PLATFORM "darwin"
+  #elif __minerva__
+    #define ARCH_PLATFORM "minerva"
+  #else
   #endif
 
   #if !defined(ARCH_PROCESSOR) || !defined(ARCH_PLATFORM)
diff --git a/src/meson.build b/src/meson.build
index a156ae3f..501914c8 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -11,20 +11,31 @@ lite_sources = [
     'main.c',
 ]
 
+lite_sources += 'api/dirmonitor.c'
 # dirmonitor backend
 if get_option('dirmonitor_backend') == ''
     if cc.has_function('inotify_init', prefix : '#include<sys/inotify.h>')
         dirmonitor_backend = 'inotify'
+        lite_sources += 'api/dirmonitor/inotify.c'
     elif host_machine.system() == 'darwin' and cc.check_header('CoreServices/CoreServices.h')
         dirmonitor_backend = 'fsevents'
+        lite_sources += 'api/dirmonitor/fsevents.c'
     elif cc.has_function('kqueue', prefix : '#include<sys/event.h>')
         dirmonitor_backend = 'kqueue'
+        lite_sources += 'api/dirmonitor/kqueue.c'
+    elif cc.has_function('create_inode_watcher', prefix : '#include<fcntl.h>')
+        dirmonitor_backend = 'inodewatcher'
+        add_languages('cpp')
+        lite_sources += 'api/dirmonitor/inodewatcher.cpp'
     elif dependency('libkqueue', required : false).found()
         dirmonitor_backend = 'kqueue'
+        lite_sources += 'api/dirmonitor/kqueue.c'
     elif host_machine.system() == 'windows'
         dirmonitor_backend = 'win32'
+        lite_sources += 'api/dirmonitor/win32.c'
     else
         dirmonitor_backend = 'dummy'
+        lite_sources += 'api/dirmonitor/dummy.c'
         warning('no suitable backend found, defaulting to dummy backend')
     endif
 else
@@ -40,12 +51,6 @@ if dirmonitor_backend == 'kqueue'
     endif
 endif
 
-lite_sources += [
-    'api/dirmonitor.c',
-    'api/dirmonitor/' + dirmonitor_backend + '.c',
-]
-
-
 lite_rc = []
 if host_machine.system() == 'windows'
     windows = import('windows')
