feat(NSPasteboard): added objective c bridge and build changes

This commit is contained in:
Grace Yoder 2026-06-29 09:45:37 -06:00
parent 2f75723e16
commit 565174c4b8
Signed by: grace
SSH key fingerprint: SHA256:oG9v0ZlohsoMAg083HAwBGOcaPLF3nIuOlAW4MtASMo
4 changed files with 48 additions and 0 deletions

View file

@ -23,6 +23,21 @@ pub fn build(b: *std.Build) void {
}),
});
if (target.result.os.tag == .macos) {
exe.root_module.addCSourceFiles(.{
.files = &.{"src/Clip/NSPBBridge.m"},
.language = .objective_c,
.flags = &.{"-fobjc-arc"},
});
exe.root_module.linkFramework("Cocoa", .{});
tests.root_module.addCSourceFiles(.{
.files = &.{"src/Clip/NSPBBridge.m"},
.language = .objective_c,
.flags = &.{"-fobjc-arc"},
});
tests.root_module.linkFramework("Cocoa", .{});
}
const test_step = b.step("test", "Run tests");
const run_tests = b.addRunArtifact(tests);
test_step.dependOn(&run_tests.step);

View file

@ -1,4 +1,5 @@
pub const OSC52 = @import("Clip/OSC52.zig");
// pub const PBCopy = if (@import("builtin").os.tag == .macos) @import("Clip/OSC52.zig") else null;
// I am not sure if this is super idiomatic Zig or if this is bad practice, but
// by ensuring that all Clip backends implement the same methods, we are able
@ -15,6 +16,8 @@ fn assertFn(comptime T: type, comptime name: []const u8, comptime Sig: type) voi
}
test {
_ = @import("Clip/NSPasteBoard.zig");
inline for (@typeInfo(@This()).@"struct".decls) |decl| {
// Only grab types of structs
const T = @field(@This(), decl.name);

12
src/Clip/NSPBBridge.m Normal file
View file

@ -0,0 +1,12 @@
// Simple bridge to objective_c code
// https://nathancraddock.com/blog/writing-to-the-clipboard-the-hard-way/
#import <Cocoa/Cocoa.h>
NSPasteboard *pboard;
void initPB() { pboard = [NSPasteboard generalPasteboard]; }
void sendPB(const char *text) {
[pboard clearContents];
[pboard setString:[NSString stringWithUTF8String:text]
forType:NSPasteboardTypeString];
}

18
src/Clip/NSPasteboard.zig Normal file
View file

@ -0,0 +1,18 @@
const std = @import("std");
extern fn sendPB(text: [*:0]const u8) void;
extern fn initPB() void;
test "objc bridge" {
initPB();
sendPB("test_string");
const result = try std.process.run(std.testing.allocator, std.testing.io, .{
.argv = &.{"pbpaste"},
});
defer std.testing.allocator.free(result.stdout);
defer std.testing.allocator.free(result.stderr);
try std.testing.expectEqualStrings("test_string", std.mem.trim(u8, result.stdout, "\n"));
}