build: add GhosttyVt module map to xcframework and Swift example
The xcframework now generates its own headers directory with a GhosttyVt module map instead of reusing include/ directly, which contains the GhosttyKit module map for the macOS app. The generated directory copies the ghostty headers and adds a module.modulemap that exposes ghostty/vt.h as the umbrella header. A new swift-vt-xcframework example demonstrates consuming the xcframework from a Swift Package. It creates a terminal, writes VT sequences, and formats the output as plain text, verifying the full round-trip works with swift build and swift run.pull/12149/head
parent
05fb57dd40
commit
f567f7f46d
|
|
@ -3,3 +3,4 @@ dist/
|
||||||
node_modules/
|
node_modules/
|
||||||
example.wasm*
|
example.wasm*
|
||||||
build/
|
build/
|
||||||
|
.build/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// swift-tools-version: 5.9
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "swift-vt-xcframework",
|
||||||
|
platforms: [.macOS(.v13)],
|
||||||
|
targets: [
|
||||||
|
.executableTarget(
|
||||||
|
name: "swift-vt-xcframework",
|
||||||
|
dependencies: ["GhosttyVt"],
|
||||||
|
path: "Sources",
|
||||||
|
linkerSettings: [
|
||||||
|
.linkedLibrary("c++"),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
.binaryTarget(
|
||||||
|
name: "GhosttyVt",
|
||||||
|
path: "../../zig-out/lib/ghostty-vt.xcframework"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# swift-vt-xcframework
|
||||||
|
|
||||||
|
Demonstrates consuming libghostty-vt from a Swift Package using the
|
||||||
|
pre-built XCFramework. Creates a terminal, writes VT sequences into it,
|
||||||
|
and formats the screen contents as plain text.
|
||||||
|
|
||||||
|
This example requires the XCFramework to be built first.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
First, build the XCFramework from the repository root:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
zig build -Demit-lib-vt
|
||||||
|
```
|
||||||
|
|
||||||
|
Then build and run the Swift package:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
cd example/swift-vt-xcframework
|
||||||
|
swift build
|
||||||
|
swift run
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import GhosttyVt
|
||||||
|
|
||||||
|
// Create a terminal with a small grid
|
||||||
|
var terminal: GhosttyTerminal?
|
||||||
|
var opts = GhosttyTerminalOptions(
|
||||||
|
cols: 80,
|
||||||
|
rows: 24,
|
||||||
|
max_scrollback: 0
|
||||||
|
)
|
||||||
|
let result = ghostty_terminal_new(nil, &terminal, opts)
|
||||||
|
guard result == GHOSTTY_SUCCESS, let terminal else {
|
||||||
|
fatalError("Failed to create terminal")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write some VT-encoded content
|
||||||
|
let text = "Hello from \u{1b}[1mSwift\u{1b}[0m via xcframework!\r\n"
|
||||||
|
text.withCString { ptr in
|
||||||
|
ghostty_terminal_vt_write(terminal, ptr, strlen(ptr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the terminal contents as plain text
|
||||||
|
var fmtOpts = GhosttyFormatterTerminalOptions()
|
||||||
|
fmtOpts.size = MemoryLayout<GhosttyFormatterTerminalOptions>.size
|
||||||
|
fmtOpts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN
|
||||||
|
fmtOpts.trim = true
|
||||||
|
|
||||||
|
var formatter: GhosttyFormatter?
|
||||||
|
let fmtResult = ghostty_formatter_terminal_new(nil, &formatter, terminal, fmtOpts)
|
||||||
|
guard fmtResult == GHOSTTY_SUCCESS, let formatter else {
|
||||||
|
fatalError("Failed to create formatter")
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf: UnsafeMutablePointer<UInt8>?
|
||||||
|
var len: Int = 0
|
||||||
|
let allocResult = ghostty_formatter_format_alloc(formatter, nil, &buf, &len)
|
||||||
|
guard allocResult == GHOSTTY_SUCCESS, let buf else {
|
||||||
|
fatalError("Failed to format")
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Plain text (\(len) bytes):")
|
||||||
|
print(String(cString: buf))
|
||||||
|
|
||||||
|
ghostty_free(nil, buf, len)
|
||||||
|
ghostty_formatter_free(formatter)
|
||||||
|
ghostty_terminal_free(terminal)
|
||||||
|
|
@ -342,12 +342,30 @@ pub fn xcframework(
|
||||||
) *XCFrameworkStep {
|
) *XCFrameworkStep {
|
||||||
assert(lib_vt.kind == .static);
|
assert(lib_vt.kind == .static);
|
||||||
const b = lib_vt.step.owner;
|
const b = lib_vt.step.owner;
|
||||||
|
|
||||||
|
// Generate a headers directory with a module map for Swift PM.
|
||||||
|
// We can't use include/ directly because it contains a module map
|
||||||
|
// for GhosttyKit (the macOS app library).
|
||||||
|
const wf = b.addWriteFiles();
|
||||||
|
_ = wf.addCopyDirectory(
|
||||||
|
b.path("include/ghostty"),
|
||||||
|
"ghostty",
|
||||||
|
.{ .include_extensions = &.{".h"} },
|
||||||
|
);
|
||||||
|
_ = wf.add("module.modulemap",
|
||||||
|
\\module GhosttyVt {
|
||||||
|
\\ umbrella header "ghostty/vt.h"
|
||||||
|
\\ export *
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
|
||||||
return XCFrameworkStep.create(b, .{
|
return XCFrameworkStep.create(b, .{
|
||||||
.name = "ghostty-vt",
|
.name = "ghostty-vt",
|
||||||
.out_path = b.pathJoin(&.{ b.install_prefix, "lib/ghostty-vt.xcframework" }),
|
.out_path = b.pathJoin(&.{ b.install_prefix, "lib/ghostty-vt.xcframework" }),
|
||||||
.libraries = &.{.{
|
.libraries = &.{.{
|
||||||
.library = lib_vt.output,
|
.library = lib_vt.output,
|
||||||
.headers = b.path("include/ghostty"),
|
.headers = wf.getDirectory(),
|
||||||
.dsym = null,
|
.dsym = null,
|
||||||
}},
|
}},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue