home
tpb

repository View

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

change ID
lopkzsklxzoknutqpprvkprzpsvxpqkv
git commit
565174c4b8c73e9e28524709060335a0b17ee3fb
author
Grace Yoder <grace_yoder@outlook.com> - 2026-06-29T09:45:37-06:00
committer
Grace Yoder <grace_yoder@outlook.com> - 2026-06-30T16:33:26-06:00
parents
korkmyurqrqo
refs
signature
Present (not validated)
feat(NSPasteboard): added objective c bridge and build changes

tree

type name size
file .crow/build.yml 2096 bytes
file .crow/release.yml 566 bytes
file .gitignore 354 bytes
file LICENSE 1073 bytes
file README.md 632 bytes
file build.zig 1579 bytes
file build.zig.zon 247 bytes
file src/Clip/NSPBBridge.m 382 bytes
file src/Clip/NSPasteboard.zig 486 bytes
file src/Clip/OSC52.zig 4611 bytes
file src/Clip.zig 1379 bytes
file src/main.zig 1466 bytes

diff

build.zig

modified (file → file)

--- a/build.zig
+++ b/build.zig
@@ -23,6 +23,21 @@
         }),
     });
 
+    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);

src/Clip/NSPBBridge.m

added (absent → file)

--- a/src/Clip/NSPBBridge.m
+++ b/src/Clip/NSPBBridge.m
@@ -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];
+}

src/Clip/NSPasteboard.zig

added (absent → file)

--- a/src/Clip/NSPasteboard.zig
+++ b/src/Clip/NSPasteboard.zig
@@ -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"));
+}
+

src/Clip.zig

modified (file → file)

--- a/src/Clip.zig
+++ b/src/Clip.zig
@@ -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 @@
 }
 
 test {
+    _ = @import("Clip/NSPasteBoard.zig");
+
     inline for (@typeInfo(@This()).@"struct".decls) |decl| {
         // Only grab types of structs
         const T = @field(@This(), decl.name);