Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/Context.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const DocumentHandler = @import("handlers/DocumentHandler.zig");
const Cache = @import("./Cache.zig");
const ReloadIndicatorTimer = @import("services/ReloadIndicatorTimer.zig");
const History = @import("services/History.zig");
const SocketServer = @import("services/SocketServer.zig");

pub const panic = vaxis.panic_handler;

Expand Down Expand Up @@ -37,6 +38,8 @@ pub const Context = struct {
current_page: ?vaxis.Image,
watcher: ?fzwatch.Watcher,
watcher_thread: ?std.Thread,
socket_server: ?SocketServer,
socket_thread: ?std.Thread,
config: *Config,
current_mode: Mode,
history: History,
Expand Down Expand Up @@ -68,6 +71,10 @@ pub const Context = struct {
watcher = try fzwatch.Watcher.init(allocator);
if (watcher) |*w| try w.addFile(path);
}
var socket_server: ?SocketServer = null;
if (config.socket_server.enabled) {
socket_server = SocketServer.init(allocator, config) catch null;
}

const vx = try vaxis.init(allocator, .{});
const buf = try allocator.alloc(u8, 4096);
Expand All @@ -87,6 +94,8 @@ pub const Context = struct {
.watcher = watcher,
.mouse = null,
.watcher_thread = null,
.socket_server = socket_server,
.socket_thread = null,
.config = config,
.current_mode = undefined,
.history = history,
Expand All @@ -110,6 +119,10 @@ pub const Context = struct {
if (self.watcher_thread) |thread| thread.join();
w.deinit();
}
if (self.socket_server) |*s| {
s.deinit();
if (self.socket_thread) |t| t.join();
}

if (self.page_info_text.len > 0) self.allocator.free(self.page_info_text);

Expand Down Expand Up @@ -138,6 +151,15 @@ pub const Context = struct {
try watcher.start(.{ .latency = self.config.file_monitor.latency });
}

fn socketWorker(server: *SocketServer, loop: *vaxis.Loop(Event)) !void {
try server.listen(loop, socketCallback);
}

fn socketCallback(context: ?*anyopaque) void {
const loop = @as(*vaxis.Loop(Event), @ptrCast(@alignCast(context.?)));
loop.postEvent(Event.file_changed);
}

pub fn run(self: *Self) !void {
self.current_mode = .{ .view = ViewMode.init(self) };

Expand Down Expand Up @@ -169,6 +191,11 @@ pub const Context = struct {
}
}
}
if (self.config.socket_server.enabled) {
if (self.socket_server) |*s| {
self.socket_thread = try std.Thread.spawn(.{}, socketWorker, .{ s, &loop });
}
}

while (!self.should_quit) {
loop.pollEvent();
Expand Down
15 changes: 15 additions & 0 deletions src/config/Config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ pub const FileMonitor = struct {
}
};

pub const SocketServer = struct {
enabled: bool = false,

pub fn parse(val: std.json.Value, allocator: std.mem.Allocator) SocketServer {
var socket_server = SocketServer{};
if (val != .object) return socket_server;

socket_server.enabled = parseType(bool, val.object, "enabled", allocator, socket_server.enabled);

return socket_server;
}
};

pub const General = struct {
colorize: bool = false,
white: i32 = 0x000000,
Expand Down Expand Up @@ -227,6 +240,7 @@ arena: std.heap.ArenaAllocator,

key_map: KeyMap = .{},
file_monitor: FileMonitor = .{},
socket_server: SocketServer = .{},
general: General = .{},
status_bar: StatusBar = .{},
cache: Cache = .{},
Expand Down Expand Up @@ -271,6 +285,7 @@ pub fn init(allocator: std.mem.Allocator) Self {

if (parsed.value.object.get("KeyMap")) |key_map| self.key_map = KeyMap.parse(key_map, arena_allocator);
if (parsed.value.object.get("FileMonitor")) |file_monitor| self.file_monitor = FileMonitor.parse(file_monitor, arena_allocator);
if (parsed.value.object.get("SocketServer")) |socket_server| self.socket_server = SocketServer.parse(socket_server, arena_allocator);
if (parsed.value.object.get("General")) |general| self.general = General.parse(general, arena_allocator);
if (parsed.value.object.get("StatusBar")) |status_bar| self.status_bar = StatusBar.parse(status_bar, arena_allocator);
if (parsed.value.object.get("Cache")) |cache| self.cache = Cache.parse(cache, arena_allocator);
Expand Down
62 changes: 62 additions & 0 deletions src/services/SocketServer.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const Self = @This();
const std = @import("std");
const Config = @import("../config/Config.zig");

allocator: std.mem.Allocator,
config: *Config,
path: []u8,
server: ?std.net.Server,
should_stop: std.atomic.Value(bool),

pub fn init(allocator: std.mem.Allocator, config: *Config) !Self {
const runtime_dir = std.process.getEnvVarOwned(allocator, "XDG_RUNTIME_DIR") catch
try allocator.dupe(u8, "/tmp");
defer allocator.free(runtime_dir);

const path = try std.fmt.allocPrint(allocator, "{s}/fancy-cat.sock", .{runtime_dir});
errdefer allocator.free(path);

// Remove a stale socket file
std.fs.deleteFileAbsolute(path) catch {};

const address = try std.net.Address.initUnix(path);
const server = try address.listen(.{ .reuse_address = true });

return .{
.allocator = allocator,
.config = config,
.path = path,
.server = server,
.should_stop = std.atomic.Value(bool).init(false),
};
}

pub fn deinit(self: *Self) void {
self.should_stop.store(true, .seq_cst);
if (self.server) |*s| {
s.deinit();
self.server = null;
}
std.fs.deleteFileAbsolute(self.path) catch {};
self.allocator.free(self.path);
self.path = &.{};
}

pub fn listen(
self: *Self,
context: ?*anyopaque,
callback: *const fn (context: ?*anyopaque) void,
) !void {
while (!self.should_stop.load(.seq_cst)) {
const conn = self.server.?.accept() catch {
if (self.should_stop.load(.seq_cst)) return;
continue;
};
defer conn.stream.close();

var buf: [64]u8 = undefined;
_ = conn.stream.read(&buf) catch continue;

callback(context);
}
}