Skip to content

Commit dc74613

Browse files
Jonathan D.A. Jewellclaude
andcommitted
FD-M06: Implement file operations with Zig FFI bindings
File Operations (FD-M06): - Add file_ops.rs with open/save/convert functions - Format detection from extension and content heuristics - Support all 7 formats (TXT, MD, ADOC, DJOT, ORG, RST, TYP) - FileInfo metadata (path, format, size, read-only) - 5 tests all passing FFI Updates: - Add formatrix_open_file, formatrix_save_file, formatrix_save_file_as - Add formatrix_detect_file_format, formatrix_format_extension - Add Copy/Clone/Debug/PartialEq to FfiResult and FfiFormat Zig Bindings: - Create bindings/zig with type-safe Zig wrapper - Document, Format, Result types with methods - Separate repo at hyperpolymath/zig-formatrix-ffi Tests: 47 passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent daa66cf commit dc74613

10 files changed

Lines changed: 1070 additions & 7 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings/zig/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Zig FFI Bindings
2+
3+
The Zig FFI bindings have been moved to a separate repository for reusability:
4+
5+
**https://github.com/hyperpolymath/zig-formatrix-ffi**
6+
7+
The files in this directory are kept for local development convenience.
8+
9+
## Building formatrix-core with FFI support
10+
11+
```bash
12+
cd ../..
13+
cargo build --release --features ffi
14+
```
15+
16+
## Using the bindings
17+
18+
See the zig-formatrix-ffi repository for full documentation and usage examples.

bindings/zig/build.zig

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: AGPL-3.0-or-later
2+
//! Build configuration for formatrix Zig bindings
3+
//!
4+
//! Links against libformatrix_core from the Rust crate.
5+
6+
const std = @import("std");
7+
8+
pub fn build(b: *std.Build) void {
9+
const target = b.standardTargetOptions(.{});
10+
const optimize = b.standardOptimizeOption(.{});
11+
12+
// Create the formatrix module
13+
const formatrix_mod = b.addModule("formatrix", .{
14+
.root_source_file = b.path("formatrix.zig"),
15+
.target = target,
16+
.optimize = optimize,
17+
});
18+
19+
// Library artifact for linking
20+
const lib = b.addStaticLibrary(.{
21+
.name = "formatrix-zig",
22+
.root_source_file = b.path("formatrix.zig"),
23+
.target = target,
24+
.optimize = optimize,
25+
});
26+
27+
// Link against the Rust library
28+
lib.addLibraryPath(.{ .cwd_relative = "../../target/release" });
29+
lib.linkSystemLibrary("formatrix_core");
30+
lib.linkLibC();
31+
32+
b.installArtifact(lib);
33+
34+
// Example executable
35+
const exe = b.addExecutable(.{
36+
.name = "formatrix-example",
37+
.root_source_file = b.path("example.zig"),
38+
.target = target,
39+
.optimize = optimize,
40+
});
41+
exe.root_module.addImport("formatrix", formatrix_mod);
42+
exe.addLibraryPath(.{ .cwd_relative = "../../target/release" });
43+
exe.linkSystemLibrary("formatrix_core");
44+
exe.linkLibC();
45+
46+
b.installArtifact(exe);
47+
48+
// Run step for example
49+
const run_cmd = b.addRunArtifact(exe);
50+
run_cmd.step.dependOn(b.getInstallStep());
51+
52+
const run_step = b.step("run", "Run the example");
53+
run_step.dependOn(&run_cmd.step);
54+
55+
// Tests
56+
const tests = b.addTest(.{
57+
.root_source_file = b.path("formatrix.zig"),
58+
.target = target,
59+
.optimize = optimize,
60+
});
61+
62+
const run_tests = b.addRunArtifact(tests);
63+
const test_step = b.step("test", "Run unit tests");
64+
test_step.dependOn(&run_tests.step);
65+
}

bindings/zig/example.zig

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: AGPL-3.0-or-later
2+
//! Example usage of formatrix Zig bindings
3+
4+
const std = @import("std");
5+
const formatrix = @import("formatrix");
6+
7+
pub fn main() !void {
8+
const allocator = std.heap.page_allocator;
9+
10+
// Print library version
11+
std.debug.print("Formatrix version: {s}\n", .{formatrix.version()});
12+
13+
// Parse some markdown
14+
const markdown_content: [:0]const u8 = "# Hello World\n\nThis is a paragraph.";
15+
16+
var doc = try formatrix.Document.parse(markdown_content, .markdown);
17+
defer doc.deinit();
18+
19+
std.debug.print("Parsed document with {d} blocks\n", .{doc.blockCount()});
20+
std.debug.print("Source format: {s}\n", .{doc.sourceFormat().label()});
21+
22+
// Get title if present
23+
if (try doc.getTitle(allocator)) |title| {
24+
defer allocator.free(title);
25+
std.debug.print("Document title: {s}\n", .{title});
26+
}
27+
28+
// Render to org-mode
29+
const org_output = try doc.render(.org_mode, allocator);
30+
defer allocator.free(org_output);
31+
32+
std.debug.print("\nRendered to Org-mode:\n{s}\n", .{org_output});
33+
34+
// Direct conversion helper
35+
const rst_output = try formatrix.convert(
36+
markdown_content,
37+
.markdown,
38+
.restructured_text,
39+
allocator,
40+
);
41+
defer allocator.free(rst_output);
42+
43+
std.debug.print("\nDirect conversion to RST:\n{s}\n", .{rst_output});
44+
45+
// Format detection
46+
const detected = formatrix.detectFormat("#+TITLE: Test\n* Heading");
47+
std.debug.print("\nDetected format for org content: {s}\n", .{detected.label()});
48+
}

0 commit comments

Comments
 (0)