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