mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-31 04:39:01 +00:00
Update to Zig 0.16.0
This commit represents the majority of the work necessary to upgrade Ghostty to use Zig 0.16.0. Key parts: * In addition to its previous responsibilities, the global state now houses state for global I/O implementations and the process environment. It is now also utilized in the main application along with the C library. Where necessary, global state is isolated from key parts of the implementation (e.g., in libghostty subsystems), and it's expected that this list will grow. * We currently manage our own C translation layer where necessary. In these cases, cImport has been removed in favor of the new external translate-c package. Due to fixes that have needed be made to properly translate the dependencies that were swapped out, as mentioned, we have had to backport fixes from the current translate-c package (and the upstream Arocc dependency). We will host this ourselves until Zig 0.17.0 is released with these fixes. * Where necessary (only a small number of cases), some stdlib code from 0.15.2 (and even from 0.17.0) has been taken, adopted, and vendored in lib/compat. Co-authored-by: Leah Amelia Chen <hi@pluie.me>
This commit is contained in:
@@ -179,4 +179,3 @@ WhitespaceSensitiveMacros:
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
---
|
||||
|
||||
|
||||
2
.github/workflows/release-tag.yml
vendored
2
.github/workflows/release-tag.yml
vendored
@@ -153,7 +153,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: XCode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
|
||||
8
.github/workflows/release-tip.yml
vendored
8
.github/workflows/release-tip.yml
vendored
@@ -362,7 +362,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Xcode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Build XCFramework
|
||||
run: nix develop -c zig build -Demit-lib-vt -Doptimize=ReleaseFast
|
||||
@@ -454,7 +454,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: XCode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
@@ -710,7 +710,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: XCode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
@@ -907,7 +907,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: XCode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
|
||||
34
.github/workflows/test.yml
vendored
34
.github/workflows/test.yml
vendored
@@ -335,7 +335,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Xcode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Build XCFramework
|
||||
run: nix develop -c zig build -Demit-lib-vt
|
||||
@@ -645,7 +645,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Xcode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
@@ -1077,7 +1077,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Xcode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
@@ -1137,7 +1137,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Xcode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
@@ -1196,9 +1196,29 @@ jobs:
|
||||
- name: Test GTK Build
|
||||
run: nix develop -c zig build -Dapp-runtime=gtk -Demit-docs -Demit-webdata
|
||||
|
||||
# This relies on the cache being populated by the commands above.
|
||||
# NOTE: This used to point to the Zig global cache directory before
|
||||
# 0.16.0. Now, the cache directory exclusively stores "minified"
|
||||
# archives of each dependency (i.e., only the paths defined in
|
||||
# build.zig.zon), and an uncompressed, working copy is stored in
|
||||
# PROJECT_ROOT/zig-pkg. The zig-pkg directory is warmed up during the
|
||||
# regular fetching process from the global cache directory if
|
||||
# possible.
|
||||
#
|
||||
# Nothing else should change; zon2nix's store path mimics what a
|
||||
# zig-pkg directory should look like, so actual build steps should be
|
||||
# fine, it's just here where we assume that all dependencies have been
|
||||
# downloaded, and we want to test the validity of the package
|
||||
# directory, do we need to have it pointing to zig-pkg and not the
|
||||
# zon2nix store path.
|
||||
#
|
||||
# Note that this can also be attempted by running:
|
||||
# zig build --fetch=needed
|
||||
#
|
||||
# Note that --system PKGDIR should not be added to this invocation as
|
||||
# it disables fetching altogether (even, seemingly, from the local
|
||||
# cache).
|
||||
- name: Test System Build
|
||||
run: nix develop -c zig build --system ${ZIG_GLOBAL_CACHE_DIR}/p
|
||||
run: nix develop -c zig build --system "$(realpath zig-pkg)"
|
||||
|
||||
test-lib-vt:
|
||||
if: github.repository == 'ghostty-org/ghostty' && needs.skip.outputs.skip != 'true'
|
||||
@@ -1377,7 +1397,7 @@ jobs:
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Xcode Select
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.6.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
|
||||
2
.github/workflows/vouch-check-issue.yml
vendored
2
.github/workflows/vouch-check-issue.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
with:
|
||||
sparse-checkout: .github/issue-unvouched-message
|
||||
|
||||
- uses: mitchellh/vouch/action/check-issue@d66fa29a64600490892131ad87597c30c91fcac4 # unreleased main
|
||||
- uses: mitchellh/vouch/action/check-issue@d66fa29a64600490892131ad87597c30c91fcac4 # v1.5.0
|
||||
with:
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
auto-close: true
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,6 +10,7 @@
|
||||
zig-cache/
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
zig-pkg/
|
||||
build-cmake/
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
@@ -29,3 +30,4 @@ glad.zip
|
||||
|
||||
vgcore.*
|
||||
|
||||
/sprite_face_test*
|
||||
|
||||
@@ -67,14 +67,6 @@ sudo xcode-select --switch /Applications/Xcode.app
|
||||
> You do not need to be running on macOS 26 to build Ghostty, you can
|
||||
> still use Xcode 26 on macOS 15 stable.
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> Zig 0.15.x has a [known linking issue](https://codeberg.org/ziglang/zig/issues/31658)
|
||||
> with **Xcode 26.4**. If you are on Xcode 26.4, you must use a
|
||||
> Homebrew-installed Zig (`brew install zig@0.15`) or our Nix flake,
|
||||
> both of which contain a patch that works around the issue. Alternatively,
|
||||
> you can downgrade to **Xcode 26.3**.
|
||||
|
||||
## AI and Agents
|
||||
|
||||
If you're using AI assistance with Ghostty, Ghostty provides an
|
||||
|
||||
50
build.zig
50
build.zig
@@ -25,9 +25,10 @@ pub fn build(b: *std.Build) !void {
|
||||
// use that as the version source of truth. Otherwise we fall back
|
||||
// to what is in the build.zig.zon.
|
||||
const file_version: ?[]const u8 = if (b.build_root.handle.readFileAlloc(
|
||||
b.allocator,
|
||||
b.graph.io,
|
||||
"VERSION",
|
||||
128,
|
||||
b.allocator,
|
||||
.limited(128),
|
||||
)) |content| std.mem.trim(
|
||||
u8,
|
||||
content,
|
||||
@@ -298,7 +299,7 @@ pub fn build(b: *std.Build) !void {
|
||||
// We need to rebuild Ghostty with a baseline CPU target.
|
||||
const valgrind_exe = exe: {
|
||||
var valgrind_config = config;
|
||||
valgrind_config.target = valgrind_config.baselineTarget();
|
||||
valgrind_config.target = valgrind_config.baselineTarget(b.graph.io);
|
||||
break :exe try buildpkg.GhosttyExe.init(
|
||||
b,
|
||||
&valgrind_config,
|
||||
@@ -343,7 +344,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.filters = test_filters,
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = config.baselineTarget(),
|
||||
.target = config.baselineTarget(b.graph.io),
|
||||
.optimize = .Debug,
|
||||
.strip = false,
|
||||
.omit_frame_pointer = false,
|
||||
@@ -352,19 +353,18 @@ pub fn build(b: *std.Build) !void {
|
||||
// Crash on x86_64 without this
|
||||
.use_llvm = true,
|
||||
});
|
||||
if (config.emit_test_exe) b.installArtifact(test_exe);
|
||||
if (config.emit_test_exe) {
|
||||
const test_exe_install = b.addInstallArtifact(test_exe, .{});
|
||||
config.addPatchElf(test_exe, &test_exe_install.step);
|
||||
test_step.dependOn(&test_exe_install.step);
|
||||
}
|
||||
_ = try deps.add(test_exe);
|
||||
|
||||
// Verify our internal libghostty header.
|
||||
const ghostty_h = b.addTranslateC(.{
|
||||
.root_source_file = b.path("include/ghostty.h"),
|
||||
.target = config.baselineTarget(),
|
||||
.optimize = .Debug,
|
||||
});
|
||||
test_exe.root_module.addImport("ghostty.h", ghostty_h.createModule());
|
||||
addGhosttyH(b, test_exe.root_module, config.baselineTarget(b.graph.io), .Debug);
|
||||
|
||||
// Normal test running
|
||||
const test_run = b.addRunArtifact(test_exe);
|
||||
config.addPatchElf(test_exe, &test_run.step);
|
||||
test_step.dependOn(&test_run.step);
|
||||
|
||||
// Normal tests always test our libghostty modules
|
||||
@@ -379,6 +379,7 @@ pub fn build(b: *std.Build) !void {
|
||||
"--gen-suppressions=all",
|
||||
});
|
||||
valgrind_run.addArtifactArg(test_exe);
|
||||
config.addPatchElf(test_exe, &valgrind_run.step);
|
||||
test_valgrind_step.dependOn(&valgrind_run.step);
|
||||
}
|
||||
|
||||
@@ -390,3 +391,28 @@ pub fn build(b: *std.Build) !void {
|
||||
try translations_step.addError("cannot update translations when i18n is disabled", .{});
|
||||
}
|
||||
}
|
||||
|
||||
fn addGhosttyH(
|
||||
b: *std.Build,
|
||||
module: *std.Build.Module,
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
) void {
|
||||
const translate_c = b.lazyImport(@This(), "translate_c") orelse return;
|
||||
const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse return;
|
||||
|
||||
const translated: translate_c.Translator = .init(translate_c_dep, .{
|
||||
.c_source_file = b.addWriteFiles().add(
|
||||
"hb_c.h",
|
||||
\\#include <ghostty.h>
|
||||
,
|
||||
),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
});
|
||||
|
||||
translated.addSystemIncludePath(b.path("include"));
|
||||
|
||||
module.addImport("ghostty.h", translated.mod);
|
||||
}
|
||||
|
||||
@@ -3,62 +3,71 @@
|
||||
.version = "1.3.2-dev",
|
||||
.paths = .{""},
|
||||
.fingerprint = 0x64407a2a0b4147e5,
|
||||
.minimum_zig_version = "0.15.2",
|
||||
.minimum_zig_version = "0.16.0",
|
||||
.dependencies = .{
|
||||
// Zig libs
|
||||
// External translate-c
|
||||
// NOTE: We might not need to keep this around forever, but we need it
|
||||
// for at least the 0.16.0 release cycle since we need fixes in
|
||||
// Aro/translate-c itself.
|
||||
.translate_c = .{
|
||||
.lazy = true,
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
},
|
||||
|
||||
// Zig libs
|
||||
.libxev = .{
|
||||
// mitchellh/libxev
|
||||
.url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
|
||||
.hash = "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs",
|
||||
.url = "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
.hash = "libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F",
|
||||
.lazy = true,
|
||||
},
|
||||
.vaxis = .{
|
||||
// rockorager/libvaxis
|
||||
.url = "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz",
|
||||
.hash = "vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS",
|
||||
.url = "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
.hash = "vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka",
|
||||
.lazy = true,
|
||||
},
|
||||
.z2d = .{
|
||||
// vancluever/z2d
|
||||
.url = "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz",
|
||||
.hash = "z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ",
|
||||
.url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz",
|
||||
.hash = "z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR",
|
||||
.lazy = true,
|
||||
},
|
||||
.zig_objc = .{
|
||||
// mitchellh/zig-objc
|
||||
.url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
|
||||
.hash = "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK",
|
||||
.url = "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
.hash = "zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi",
|
||||
.lazy = true,
|
||||
},
|
||||
.zig_js = .{
|
||||
// mitchellh/zig-js
|
||||
.url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
|
||||
.hash = "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi",
|
||||
.url = "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
.hash = "zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj",
|
||||
.lazy = true,
|
||||
},
|
||||
.uucode = .{
|
||||
// jacobsandlund/uucode
|
||||
.url = "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz",
|
||||
.hash = "uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9",
|
||||
.url = "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
.hash = "uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA",
|
||||
},
|
||||
.zig_wayland = .{
|
||||
// codeberg ifreund/zig-wayland
|
||||
.url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
|
||||
.hash = "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe",
|
||||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz",
|
||||
.hash = "wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX",
|
||||
.lazy = true,
|
||||
},
|
||||
.zf = .{
|
||||
// natecraddock/zf
|
||||
.url = "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz",
|
||||
.hash = "zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh",
|
||||
.url = "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
.hash = "zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW",
|
||||
.lazy = true,
|
||||
},
|
||||
.gobject = .{
|
||||
// https://github.com/ghostty-org/zig-gobject based on zig_gobject
|
||||
// Temporary until we generate them at build time automatically.
|
||||
.url = "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst",
|
||||
.hash = "gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-",
|
||||
.url = "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst",
|
||||
.hash = "gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
|
||||
78
build.zig.zon.json
generated
78
build.zig.zon.json
generated
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"aro-0.0.0-JSD1Qk8rOQDnuVcD4jAwMpHitA6pADRKzQ7M7hKRwxvD": {
|
||||
"name": "aro",
|
||||
"url": "https://github.com/vancluever/arocc/archive/ecbc5c799574e0da2758a961b12efa586007f03c.tar.gz",
|
||||
"hash": "sha256-rjNfhWjmA/1WR/xuHo4ls4fnDCbsI1VZSvb8SFRvwso="
|
||||
},
|
||||
"N-V-__8AANT61wB--nJ95Gj_ctmzAtcjloZ__hRqNw5lC1Kr": {
|
||||
"name": "bindings",
|
||||
"url": "https://deps.files.ghostty.org/DearBindings_v0.17_ImGui_v1.92.5-docking.tar.gz",
|
||||
@@ -29,10 +34,10 @@
|
||||
"url": "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz",
|
||||
"hash": "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U="
|
||||
},
|
||||
"gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-": {
|
||||
"gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp": {
|
||||
"name": "gobject",
|
||||
"url": "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst",
|
||||
"hash": "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc="
|
||||
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst",
|
||||
"hash": "sha256-cZGf9a1+sDeORKWYIdzQ/5KLT7l/9pgPc2cIbqfBc4o="
|
||||
},
|
||||
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
|
||||
"name": "gtk4_layer_shell",
|
||||
@@ -69,10 +74,10 @@
|
||||
"url": "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz",
|
||||
"hash": "sha256-/syVtGzwXo4/yKQUdQ4LparQDYnp/fF16U/wQcrxoDo="
|
||||
},
|
||||
"libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs": {
|
||||
"libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F": {
|
||||
"name": "libxev",
|
||||
"url": "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
|
||||
"hash": "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg="
|
||||
"url": "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
"hash": "sha256-fOU1oxIxfoEgoLuWz7fVX6M+zmqpo7gqZObWiH/aDE0="
|
||||
},
|
||||
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
|
||||
"name": "libxml2",
|
||||
@@ -109,20 +114,25 @@
|
||||
"url": "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz",
|
||||
"hash": "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M="
|
||||
},
|
||||
"uucode-0.1.0-ZZjBPj96QADXyt5sqwBJUnhaDYs_qBeeKijZvlRa0eqM": {
|
||||
"name": "uucode",
|
||||
"url": "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732",
|
||||
"hash": "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8="
|
||||
"translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB": {
|
||||
"name": "translate_c",
|
||||
"url": "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
"hash": "sha256-i7TSSiLU9YGtLtEjgVqy2jSnKLDTeKHX+EFuXEMXJ+U="
|
||||
},
|
||||
"uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9": {
|
||||
"uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA": {
|
||||
"name": "uucode",
|
||||
"url": "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz",
|
||||
"hash": "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg="
|
||||
"url": "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
"hash": "sha256-R5RXW5tWIaDq5JOF2+oWd5YOYOyns6WH7f687WE+b20="
|
||||
},
|
||||
"vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS": {
|
||||
"vaxis-0.6.0-BWNV_MjFCQCs9UDHiRkrgw_ayeiPkzOe4xVbaAqXkUWW": {
|
||||
"name": "vaxis",
|
||||
"url": "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz",
|
||||
"hash": "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y="
|
||||
"url": "git+https://github.com/rockorager/libvaxis.git#c1e1f23be38951c425cdf31af455ba23ef178940",
|
||||
"hash": "sha256-bIXu8lGwGo42QbItC0jOi/eN7u+f4snknBexw7dc0DI="
|
||||
},
|
||||
"vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka": {
|
||||
"name": "vaxis",
|
||||
"url": "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"hash": "sha256-z3J3w+oYapfAZZR+MvWXwg+th1hePDA1TptnKFO4r+M="
|
||||
},
|
||||
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
|
||||
"name": "wayland",
|
||||
@@ -144,35 +154,35 @@
|
||||
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
||||
"hash": "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="
|
||||
},
|
||||
"z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ": {
|
||||
"z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR": {
|
||||
"name": "z2d",
|
||||
"url": "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz",
|
||||
"hash": "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E="
|
||||
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz",
|
||||
"hash": "sha256-/Yje2P+ro7IrPodQ26YKk7RsPSYj1Cqx6bdrmykXEKA="
|
||||
},
|
||||
"zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh": {
|
||||
"zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW": {
|
||||
"name": "zf",
|
||||
"url": "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz",
|
||||
"hash": "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY="
|
||||
"url": "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
"hash": "sha256-LHurWwqK8jhP8AZd/CXrMJNeVsKftRCTN31/EgEgKaA="
|
||||
},
|
||||
"zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi": {
|
||||
"zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj": {
|
||||
"name": "zig_js",
|
||||
"url": "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
|
||||
"hash": "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4="
|
||||
"url": "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
"hash": "sha256-Q1643wb/MCX0QkPa9QEY9xeQbqpC2IOrjER0ZyL3mH0="
|
||||
},
|
||||
"zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK": {
|
||||
"zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi": {
|
||||
"name": "zig_objc",
|
||||
"url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
|
||||
"hash": "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM="
|
||||
"url": "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
"hash": "sha256-t8cTTJm0crcoGAyOqXO0wB2w7Yit80J2Orwr6prd/G0="
|
||||
},
|
||||
"wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe": {
|
||||
"wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX": {
|
||||
"name": "zig_wayland",
|
||||
"url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
|
||||
"hash": "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw="
|
||||
"url": "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz",
|
||||
"hash": "sha256-3m/ITNhZUJ/5uD/Tqm+0uZSktGoYgWF5oldOqOCUkIE="
|
||||
},
|
||||
"zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms": {
|
||||
"zigimg-0.1.0-8_eo2oyaFwBZwJpmqPkCfVXWBrHcqbYwmrp1I6bTD3lI": {
|
||||
"name": "zigimg",
|
||||
"url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
|
||||
"hash": "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A="
|
||||
"url": "git+https://github.com/zigimg/zigimg#d695acd97c02e57bb151e8f659d1280f5cd6ca70",
|
||||
"hash": "sha256-0IYATQldT6eJxRR2T/2CsIYZuzomqjvmdVyjmsjguyE="
|
||||
},
|
||||
"N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
|
||||
"name": "zlib",
|
||||
|
||||
100
build.zig.zon.nix
generated
100
build.zig.zon.nix
generated
@@ -6,7 +6,7 @@
|
||||
fetchurl,
|
||||
fetchgit,
|
||||
runCommandLocal,
|
||||
zig_0_15,
|
||||
zig_0_16,
|
||||
zstd,
|
||||
name ? "zig-packages",
|
||||
}: let
|
||||
@@ -16,12 +16,16 @@
|
||||
}:
|
||||
runCommandLocal name
|
||||
{
|
||||
nativeBuildInputs = [zig_0_15];
|
||||
nativeBuildInputs = [zig_0_16];
|
||||
}
|
||||
''
|
||||
hash="$(cd "$TMPDIR" && zig fetch --global-cache-dir "$TMPDIR" ${artifact})"
|
||||
mv "$TMPDIR/p/$hash" "$out"
|
||||
chmod 755 "$out"
|
||||
# workaround https://codeberg.org/ziglang/zig/issues/31866
|
||||
# https://github.com/Cloudef/zig2nix/issues/54
|
||||
mkdir "$TMPDIR/src" "$TMPDIR/cache"
|
||||
touch "$TMPDIR/src/build.zig"
|
||||
hash="$(cd "$TMPDIR/src" && zig fetch --global-cache-dir "$TMPDIR/cache" ${artifact})"
|
||||
mkdir "$out"
|
||||
tar zxvf "$TMPDIR/cache/p/$hash.tar.gz" --directory "$out/" --strip-components=1
|
||||
'';
|
||||
|
||||
fetchZig = {
|
||||
@@ -93,6 +97,15 @@
|
||||
fetcher.${proto};
|
||||
in
|
||||
linkFarm name [
|
||||
{
|
||||
name = "aro-0.0.0-JSD1Qk8rOQDnuVcD4jAwMpHitA6pADRKzQ7M7hKRwxvD";
|
||||
path = fetchZigArtifact {
|
||||
name = "aro";
|
||||
url = "https://github.com/vancluever/arocc/archive/ecbc5c799574e0da2758a961b12efa586007f03c.tar.gz";
|
||||
hash = "sha256-rjNfhWjmA/1WR/xuHo4ls4fnDCbsI1VZSvb8SFRvwso=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AANT61wB--nJ95Gj_ctmzAtcjloZ__hRqNw5lC1Kr";
|
||||
path = fetchZigArtifact {
|
||||
@@ -148,11 +161,11 @@ in
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-";
|
||||
name = "gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp";
|
||||
path = fetchZigArtifact {
|
||||
name = "gobject";
|
||||
url = "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst";
|
||||
hash = "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc=";
|
||||
url = "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst";
|
||||
hash = "sha256-cZGf9a1+sDeORKWYIdzQ/5KLT7l/9pgPc2cIbqfBc4o=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
@@ -220,11 +233,11 @@ in
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs";
|
||||
name = "libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F";
|
||||
path = fetchZigArtifact {
|
||||
name = "libxev";
|
||||
url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz";
|
||||
hash = "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg=";
|
||||
url = "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz";
|
||||
hash = "sha256-fOU1oxIxfoEgoLuWz7fVX6M+zmqpo7gqZObWiH/aDE0=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
@@ -292,29 +305,38 @@ in
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "uucode-0.1.0-ZZjBPj96QADXyt5sqwBJUnhaDYs_qBeeKijZvlRa0eqM";
|
||||
name = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB";
|
||||
path = fetchZigArtifact {
|
||||
name = "uucode";
|
||||
url = "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732";
|
||||
hash = "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8=";
|
||||
name = "translate_c";
|
||||
url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz";
|
||||
hash = "sha256-i7TSSiLU9YGtLtEjgVqy2jSnKLDTeKHX+EFuXEMXJ+U=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9";
|
||||
name = "uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA";
|
||||
path = fetchZigArtifact {
|
||||
name = "uucode";
|
||||
url = "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz";
|
||||
hash = "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg=";
|
||||
url = "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz";
|
||||
hash = "sha256-R5RXW5tWIaDq5JOF2+oWd5YOYOyns6WH7f687WE+b20=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS";
|
||||
name = "vaxis-0.6.0-BWNV_MjFCQCs9UDHiRkrgw_ayeiPkzOe4xVbaAqXkUWW";
|
||||
path = fetchZigArtifact {
|
||||
name = "vaxis";
|
||||
url = "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz";
|
||||
hash = "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y=";
|
||||
url = "git+https://github.com/rockorager/libvaxis.git#c1e1f23be38951c425cdf31af455ba23ef178940";
|
||||
hash = "sha256-bIXu8lGwGo42QbItC0jOi/eN7u+f4snknBexw7dc0DI=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka";
|
||||
path = fetchZigArtifact {
|
||||
name = "vaxis";
|
||||
url = "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz";
|
||||
hash = "sha256-z3J3w+oYapfAZZR+MvWXwg+th1hePDA1TptnKFO4r+M=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
@@ -355,56 +377,56 @@ in
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ";
|
||||
name = "z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR";
|
||||
path = fetchZigArtifact {
|
||||
name = "z2d";
|
||||
url = "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz";
|
||||
hash = "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E=";
|
||||
url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz";
|
||||
hash = "sha256-/Yje2P+ro7IrPodQ26YKk7RsPSYj1Cqx6bdrmykXEKA=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh";
|
||||
name = "zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW";
|
||||
path = fetchZigArtifact {
|
||||
name = "zf";
|
||||
url = "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz";
|
||||
hash = "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY=";
|
||||
url = "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz";
|
||||
hash = "sha256-LHurWwqK8jhP8AZd/CXrMJNeVsKftRCTN31/EgEgKaA=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi";
|
||||
name = "zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj";
|
||||
path = fetchZigArtifact {
|
||||
name = "zig_js";
|
||||
url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz";
|
||||
hash = "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4=";
|
||||
url = "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz";
|
||||
hash = "sha256-Q1643wb/MCX0QkPa9QEY9xeQbqpC2IOrjER0ZyL3mH0=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK";
|
||||
name = "zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi";
|
||||
path = fetchZigArtifact {
|
||||
name = "zig_objc";
|
||||
url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz";
|
||||
hash = "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM=";
|
||||
url = "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz";
|
||||
hash = "sha256-t8cTTJm0crcoGAyOqXO0wB2w7Yit80J2Orwr6prd/G0=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe";
|
||||
name = "wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX";
|
||||
path = fetchZigArtifact {
|
||||
name = "zig_wayland";
|
||||
url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz";
|
||||
hash = "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw=";
|
||||
url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz";
|
||||
hash = "sha256-3m/ITNhZUJ/5uD/Tqm+0uZSktGoYgWF5oldOqOCUkIE=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms";
|
||||
name = "zigimg-0.1.0-8_eo2oyaFwBZwJpmqPkCfVXWBrHcqbYwmrp1I6bTD3lI";
|
||||
path = fetchZigArtifact {
|
||||
name = "zigimg";
|
||||
url = "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz";
|
||||
hash = "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A=";
|
||||
url = "git+https://github.com/zigimg/zigimg#d695acd97c02e57bb151e8f659d1280f5cd6ca70";
|
||||
hash = "sha256-0IYATQldT6eJxRR2T/2CsIYZuzomqjvmdVyjmsjguyE=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
|
||||
24
build.zig.zon.txt
generated
24
build.zig.zon.txt
generated
@@ -1,4 +1,7 @@
|
||||
git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732
|
||||
git+https://github.com/rockorager/libvaxis.git#c1e1f23be38951c425cdf31af455ba23ef178940
|
||||
git+https://github.com/zigimg/zigimg#d695acd97c02e57bb151e8f659d1280f5cd6ca70
|
||||
https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz
|
||||
https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz
|
||||
https://deps.files.ghostty.org/DearBindings_v0.17_ImGui_v1.92.5-docking.tar.gz
|
||||
https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz
|
||||
https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz
|
||||
@@ -8,29 +11,28 @@ https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab0
|
||||
https://deps.files.ghostty.org/gettext-0.24.tar.gz
|
||||
https://deps.files.ghostty.org/ghostty-themes-release-20260713-155359-c3968b3.tgz
|
||||
https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz
|
||||
https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst
|
||||
https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz
|
||||
https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz
|
||||
https://deps.files.ghostty.org/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz
|
||||
https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz
|
||||
https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz
|
||||
https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz
|
||||
https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz
|
||||
https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d83b5801a932dcd44917424c8806.tar.gz
|
||||
https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz
|
||||
https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz
|
||||
https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz
|
||||
https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz
|
||||
https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz
|
||||
https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz
|
||||
https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz
|
||||
https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz
|
||||
https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz
|
||||
https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz
|
||||
https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz
|
||||
https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz
|
||||
https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz
|
||||
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
|
||||
https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
|
||||
https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst
|
||||
https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz
|
||||
https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz
|
||||
https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz
|
||||
https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz
|
||||
https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz
|
||||
https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz
|
||||
https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz
|
||||
https://github.com/vancluever/arocc/archive/ecbc5c799574e0da2758a961b12efa586007f03c.tar.gz
|
||||
https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz
|
||||
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
const std = @import("std");
|
||||
const ghostty_vt = @import("ghostty-vt");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer _ = gpa.deinit();
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
// Create a terminal
|
||||
var t: ghostty_vt.Terminal = try .init(alloc, .{ .cols = 150, .rows = 80 });
|
||||
defer t.deinit(alloc);
|
||||
var t: ghostty_vt.Terminal = try .init(init.io, init.gpa, .{ .cols = 150, .rows = 80 });
|
||||
defer t.deinit(init.gpa);
|
||||
|
||||
// Create a read-only VT stream for parsing terminal sequences
|
||||
var stream = t.vtStream();
|
||||
defer stream.deinit();
|
||||
|
||||
// Read from stdin
|
||||
const stdin = std.fs.File.stdin();
|
||||
const stdin = std.Io.File.stdin();
|
||||
var buf: [4096]u8 = undefined;
|
||||
while (true) {
|
||||
const n = try stdin.readAll(&buf);
|
||||
const n = try stdin.readStreaming(init.io, &.{&buf});
|
||||
if (n == 0) break;
|
||||
|
||||
// Replace \n with \r\n
|
||||
@@ -35,7 +31,7 @@ pub fn main() !void {
|
||||
});
|
||||
|
||||
// Write to stdout
|
||||
var stdout_writer = std.fs.File.stdout().writer(&buf);
|
||||
var stdout_writer = std.Io.File.stdout().writer(init.io, &buf);
|
||||
const stdout = &stdout_writer.interface;
|
||||
try stdout.print("{f}", .{formatter});
|
||||
try stdout.flush();
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
const std = @import("std");
|
||||
const ghostty_vt = @import("ghostty-vt");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer _ = gpa.deinit();
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
var t: ghostty_vt.Terminal = try .init(alloc, .{ .cols = 80, .rows = 24 });
|
||||
defer t.deinit(alloc);
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
var t: ghostty_vt.Terminal = try .init(init.io, init.gpa, .{ .cols = 80, .rows = 24 });
|
||||
defer t.deinit(init.gpa);
|
||||
|
||||
// Create a read-only VT stream for parsing terminal sequences
|
||||
var stream = t.vtStream();
|
||||
@@ -34,7 +30,7 @@ pub fn main() !void {
|
||||
stream.nextSlice("Line A\r\nLine B\r\nLine C\r\n");
|
||||
|
||||
// Get the final terminal state as a plain string
|
||||
const str = try t.plainString(alloc);
|
||||
defer alloc.free(str);
|
||||
const str = try t.plainString(init.gpa);
|
||||
defer init.gpa.free(str);
|
||||
std.debug.print("{s}\n", .{str});
|
||||
}
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
const std = @import("std");
|
||||
const ghostty_vt = @import("ghostty-vt");
|
||||
|
||||
pub fn main() !void {
|
||||
// Use a debug allocator so we get leak checking. You probably want
|
||||
// to replace this for release builds.
|
||||
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer _ = gpa.deinit();
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
// Initialize a terminal.
|
||||
var t: ghostty_vt.Terminal = try .init(alloc, .{
|
||||
var t: ghostty_vt.Terminal = try .init(init.io, init.gpa, .{
|
||||
.cols = 6,
|
||||
.rows = 40,
|
||||
});
|
||||
defer t.deinit(alloc);
|
||||
defer t.deinit(init.gpa);
|
||||
|
||||
// Write some text. It'll wrap because this is too long for our
|
||||
// columns size above (6).
|
||||
try t.printString("Hello, World!");
|
||||
|
||||
// Get the plain string view of the terminal screen.
|
||||
const str = try t.plainString(alloc);
|
||||
defer alloc.free(str);
|
||||
const str = try t.plainString(init.gpa);
|
||||
defer init.gpa.free(str);
|
||||
std.debug.print("{s}\n", .{str});
|
||||
}
|
||||
|
||||
56
flake.lock
generated
56
flake.lock
generated
@@ -3,11 +3,11 @@
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1761588595,
|
||||
"narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
|
||||
"lastModified": 1767039857,
|
||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
|
||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -23,11 +23,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1770586272,
|
||||
"narHash": "sha256-Ucci8mu8QfxwzyfER2DQDbvW9t1BnTUJhBmY7ybralo=",
|
||||
"lastModified": 1782657028,
|
||||
"narHash": "sha256-PHTCpYZCMzJYS3phhywqRAZphKVr2zjvlGYa+H20ZZ4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "b1f916ba052341edc1f80d4b2399f1092a4873ca",
|
||||
"rev": "4ad9aaae70c9aaab504127f926c0fa9cfbc2b365",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -38,11 +38,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1770537093,
|
||||
"narHash": "sha256-XV30uo8tXuxdzuV8l3sojmlPRLd/8tpMsOp4lNzLGUo=",
|
||||
"rev": "fef9403a3e4d31b0a23f0bacebbec52c248fbb51",
|
||||
"lastModified": 1782545840,
|
||||
"narHash": "sha256-CAi8oAZaE6pTkcYQBnnOlvmfMgG/p1AO0FohKKN3J7I=",
|
||||
"rev": "3d46470bb3030020f7e1361f33514854f5bfa86d",
|
||||
"type": "tarball",
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre942631.fef9403a3e4d/nixexprs.tar.xz"
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1023445.3d46470bb303/nixexprs.tar.xz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
@@ -88,11 +88,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1776789209,
|
||||
"narHash": "sha256-G6B7Q4TXn7MZ1mB+f9rymjsYF5PLWoSvmbxijb/99bw=",
|
||||
"lastModified": 1782609341,
|
||||
"narHash": "sha256-OfCPJFS/2Z2ZyjE4adR7PL+ZEqvDQFi2XNI1L8s6wKU=",
|
||||
"owner": "mitchellh",
|
||||
"repo": "zig-overlay",
|
||||
"rev": "14fe971844e841297ddd2ce9783d6892b467af39",
|
||||
"rev": "5386fea92c45b154bbeb52d14ef5504f82eda86c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -101,40 +101,18 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zig_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zon2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777234348,
|
||||
"narHash": "sha256-fKw44a4qbUuI5eTG8k0gPbqMV5TOrjYF35PBzsYgd2U=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "2c781c0609ecda600ab98f98cca417bbd981bd53",
|
||||
"revCount": 1677,
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/jcollie/zig-overlay.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/jcollie/zig-overlay.git"
|
||||
}
|
||||
},
|
||||
"zon2nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"zig": "zig_2"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777314365,
|
||||
"narHash": "sha256-eLxQaD0wc96Neqkln8wHS0rNq/chPODifFkhwrwilEU=",
|
||||
"lastModified": 1784117571,
|
||||
"narHash": "sha256-Hvnmnuu0VpHiZl+8z+UkMoxC7JZJvRYBqu2Asb0ZJOE=",
|
||||
"owner": "jcollie",
|
||||
"repo": "zon2nix",
|
||||
"rev": "a5a1d412ad1ab6305511997bbc92b3a9dd6cb784",
|
||||
"rev": "0ce628fb78309cdb13d098ae9c6fdbf87c75d25b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
49
flake.nix
49
flake.nix
@@ -74,23 +74,42 @@
|
||||
};
|
||||
in {
|
||||
devShells = forAllPlatforms (pkgs: {
|
||||
default = pkgs.callPackage ./nix/devShell.nix {
|
||||
zig =
|
||||
if pkgs.stdenv.hostPlatform.isDarwin
|
||||
then zig.packages.${pkgs.stdenv.hostPlatform.system}.brew."0.15.2"
|
||||
else zig.packages.${pkgs.stdenv.hostPlatform.system}."0.15.2";
|
||||
wraptest = pkgs.callPackage ./nix/pkgs/wraptest.nix {};
|
||||
zon2nix = zon2nix;
|
||||
default =
|
||||
pkgs.callPackage ./nix/devShell.nix
|
||||
(let
|
||||
libfyaml =
|
||||
if pkgs.stdenv.hostPlatform.isDarwin
|
||||
then
|
||||
pkgs.libfyaml.overrideAttrs (prev: {
|
||||
# Manually fix libfyaml.pc until NixOS/nixpkgs#515614 is available
|
||||
postInstall =
|
||||
(prev.postInstall or "")
|
||||
+ ''
|
||||
substituteInPlace "$dev/lib/pkgconfig/libfyaml.pc" \
|
||||
--replace-fail " none required" ""
|
||||
'';
|
||||
})
|
||||
else pkgs.libfyaml;
|
||||
|
||||
python3 = pkgs.python3.override {
|
||||
self = pkgs.python3;
|
||||
packageOverrides = pyfinal: pyprev: {
|
||||
blessed = pyfinal.callPackage ./nix/pkgs/blessed.nix {};
|
||||
ucs-detect = pyfinal.callPackage ./nix/pkgs/ucs-detect.nix {};
|
||||
wcwidth = pyfinal.callPackage ./nix/pkgs/wcwidth.nix {};
|
||||
appstream = pkgs.appstream.override {libfyaml = libfyaml;};
|
||||
libadwaita = pkgs.libadwaita.override {appstream = appstream;};
|
||||
blueprint-compiler = pkgs.blueprint-compiler.override {libadwaita = libadwaita;};
|
||||
in {
|
||||
zig = zig.packages.${pkgs.stdenv.hostPlatform.system}."0.16.0";
|
||||
wraptest = pkgs.callPackage ./nix/pkgs/wraptest.nix {};
|
||||
zon2nix = zon2nix;
|
||||
|
||||
python3 = pkgs.python3.override {
|
||||
self = pkgs.python3;
|
||||
packageOverrides = pyfinal: pyprev: {
|
||||
blessed = pyfinal.callPackage ./nix/pkgs/blessed.nix {};
|
||||
ucs-detect = pyfinal.callPackage ./nix/pkgs/ucs-detect.nix {};
|
||||
wcwidth = pyfinal.callPackage ./nix/pkgs/wcwidth.nix {};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inherit appstream libadwaita blueprint-compiler;
|
||||
});
|
||||
});
|
||||
|
||||
packages =
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
[
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/vancluever/arocc/archive/ecbc5c799574e0da2758a961b12efa586007f03c.tar.gz",
|
||||
"dest": "vendor/p/aro-0.0.0-JSD1Qk8rOQDnuVcD4jAwMpHitA6pADRKzQ7M7hKRwxvD",
|
||||
"sha256": "aa54487bd727e8fa36744ff0a824dedb2f4ca45f4c2d4d9d2437cf5fd3d0ad1a"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/DearBindings_v0.17_ImGui_v1.92.5-docking.tar.gz",
|
||||
@@ -37,9 +43,9 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst",
|
||||
"dest": "vendor/p/gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-",
|
||||
"sha256": "d9bd4306f0081d8e4b848b6adfeabd2fab49822ee2b679eb4801dcedf5d60c48"
|
||||
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst",
|
||||
"dest": "vendor/p/gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp",
|
||||
"sha256": "642e324b3644c00464a2161e4af497f73cbbe8ce02a4c0edb92aacb365748047"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
@@ -85,9 +91,9 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
|
||||
"dest": "vendor/p/libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs",
|
||||
"sha256": "6003ea6b96e4a518a128f932327d79a11bd30996b13b73baeb29916379487dd7"
|
||||
"url": "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
"dest": "vendor/p/libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F",
|
||||
"sha256": "e2b9b224cd78101156abb8f46479a51f6cce66c4815c632856e20a1440dd02b7"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
@@ -131,23 +137,29 @@
|
||||
"dest": "vendor/p/N-V-__8AANb6pwD7O1WG6L5nvD_rNMvnSc9Cpg1ijSlTYywv",
|
||||
"sha256": "b52b6fcfc45e7fa69b1f06a1362c155473444e2cc09995556b156c53ba6657e3"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
"dest": "vendor/p/translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
"sha256": "4fd2a2b21dbc49c22bea6854a59a7568dc77183760531ace3cf8da1267696afd"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz",
|
||||
"dest": "vendor/p/uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA",
|
||||
"sha256": "7e76fc7fab1e7ac728c52b35bbb3e5b8c639841abfc7fe1a4bcb13050594bc9e"
|
||||
},
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/jacobsandlund/uucode",
|
||||
"commit": "5f05f8f83a75caea201f12cc8ea32a2d82ea9732",
|
||||
"dest": "vendor/p/uucode-0.1.0-ZZjBPj96QADXyt5sqwBJUnhaDYs_qBeeKijZvlRa0eqM"
|
||||
"url": "https://github.com/rockorager/libvaxis.git",
|
||||
"commit": "c1e1f23be38951c425cdf31af455ba23ef178940",
|
||||
"dest": "vendor/p/vaxis-0.6.0-BWNV_MjFCQCs9UDHiRkrgw_ayeiPkzOe4xVbaAqXkUWW"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz",
|
||||
"dest": "vendor/p/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9",
|
||||
"sha256": "d0abee0f4f8bd6eae3c051777e16e7c42d8964aaaa015591c4e565703f465f95"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz",
|
||||
"dest": "vendor/p/vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS",
|
||||
"sha256": "2e72332bc89c5b541ec6e6bd48769e1f3fb757c4006f3d1af940b54f9b088ef6"
|
||||
"url": "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"dest": "vendor/p/vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka",
|
||||
"sha256": "3ea050e905887c46bca1a2c18e41d6edf574c1aa6ebfbc5cf3c52846275e4fa8"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
@@ -175,39 +187,39 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz",
|
||||
"dest": "vendor/p/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ",
|
||||
"sha256": "69f21da2efd5ee0937fe55c4d09e48afc4fb2f91a01ef167c8c275ae046797f7"
|
||||
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz",
|
||||
"dest": "vendor/p/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR",
|
||||
"sha256": "d48b117307f767ca379bf31bd171880e66dcafb89eca4a8f923222619992fcb4"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz",
|
||||
"dest": "vendor/p/zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh",
|
||||
"sha256": "3b015d928af04e9e26272bc15eb4dbb4d9a9d469eb6d290a0ddae673b77c4568"
|
||||
"url": "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz",
|
||||
"dest": "vendor/p/zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW",
|
||||
"sha256": "ca4bc109fd9d97cedae2f5bdb879cc78c346d43c14a34e3a2abd2ee9208c8547"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
|
||||
"dest": "vendor/p/zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi",
|
||||
"sha256": "4c2018e56015d39504b8090386ad9ce9393f38380085d9c32373bf7e56fc73a3"
|
||||
"url": "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz",
|
||||
"dest": "vendor/p/zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj",
|
||||
"sha256": "a2ff488a244301f4e59469a5232aad6869b01acc50f7d7ed2647c029a57d4b3b"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
|
||||
"dest": "vendor/p/zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK",
|
||||
"sha256": "dd84af737625356fcd722cb30909f3b2e8d702667cf579714aa7eabc0ac08ecc"
|
||||
"url": "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz",
|
||||
"dest": "vendor/p/zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi",
|
||||
"sha256": "831eaec554bb23ef20229f1e705d8f53e8a29c829840bb8d0f5edb05c76d6df0"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
|
||||
"dest": "vendor/p/wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe",
|
||||
"sha256": "4f146b735ed0d527f520e3bf71d3e93f72c3d0fa583ae8edd3a4851f7079124e"
|
||||
"url": "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz",
|
||||
"dest": "vendor/p/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX",
|
||||
"sha256": "759a632e36a948e0e412d2d74a43a69d2f34e65d40289a16af7aa3725852ef25"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
|
||||
"dest": "vendor/p/zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms",
|
||||
"sha256": "2c1ed76ba2b35514544b0c27c9633ecba7c31be9080e37e7a010c93b5a1bc553"
|
||||
"type": "git",
|
||||
"url": "https://github.com/zigimg/zigimg",
|
||||
"commit": "d695acd97c02e57bb151e8f659d1280f5cd6ca70",
|
||||
"dest": "vendor/p/zigimg-0.1.0-8_eo2oyaFwBZwJpmqPkCfVXWBrHcqbYwmrp1I6bTD3lI"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
|
||||
@@ -79,7 +79,7 @@ elif [ "$1" != "--update" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
zon2nix "$BUILD_ZIG_ZON" --15 --nix "$WORK_DIR/build.zig.zon.nix" --txt "$WORK_DIR/build.zig.zon.txt" --json "$WORK_DIR/build.zig.zon.json" --flatpak "$WORK_DIR/zig-packages.json"
|
||||
zon2nix "$BUILD_ZIG_ZON" --16 --nix "$WORK_DIR/build.zig.zon.nix" --txt "$WORK_DIR/build.zig.zon.txt" --json "$WORK_DIR/build.zig.zon.json" --flatpak "$WORK_DIR/zig-packages.json"
|
||||
alejandra --quiet "$WORK_DIR/build.zig.zon.nix"
|
||||
prettier --log-level warn --write "$WORK_DIR/build.zig.zon.json"
|
||||
prettier --log-level warn --write "$WORK_DIR/zig-packages.json"
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
wasmtime,
|
||||
wraptest,
|
||||
zig,
|
||||
zig_0_15,
|
||||
zip,
|
||||
llvmPackages_latest,
|
||||
bzip2,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
versionCheckHook,
|
||||
darwin,
|
||||
xcbuild,
|
||||
zig_0_15,
|
||||
zig_0_16,
|
||||
revision ? "dirty",
|
||||
optimize ? "Debug",
|
||||
simd ? true,
|
||||
@@ -59,7 +59,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
[
|
||||
git
|
||||
pkg-config
|
||||
zig_0_15
|
||||
zig_0_16
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
darwin.cctools
|
||||
@@ -264,7 +264,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
meta = {
|
||||
homepage = "https://ghostty.org";
|
||||
license = lib.licenses.mit;
|
||||
platforms = zig_0_15.meta.platforms;
|
||||
platforms = zig_0_16.meta.platforms;
|
||||
pkgConfigModules = [
|
||||
"libghostty-vt"
|
||||
"libghostty-vt-static"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
git,
|
||||
ncurses,
|
||||
pkg-config,
|
||||
zig_0_15,
|
||||
zig_0_16,
|
||||
pandoc,
|
||||
revision ? "dirty",
|
||||
optimize ? "Debug",
|
||||
@@ -63,7 +63,7 @@ in
|
||||
ncurses
|
||||
pandoc
|
||||
pkg-config
|
||||
zig_0_15
|
||||
zig_0_16
|
||||
gobject-introspection
|
||||
wrapGAppsHook4
|
||||
blueprint-compiler
|
||||
|
||||
@@ -118,16 +118,16 @@ pub fn addPaths(b: *std.Build, step: *std.Build.Step.Compile) !void {
|
||||
|
||||
fn findNDKPath(b: *std.Build) ?[]const u8 {
|
||||
// Check if user has set the environment variable for the NDK path.
|
||||
if (std.process.getEnvVarOwned(b.allocator, "ANDROID_NDK_HOME") catch null) |value| {
|
||||
if (b.graph.environ_map.get("ANDROID_NDK_HOME")) |value| {
|
||||
if (value.len == 0) return null;
|
||||
var dir = std.fs.openDirAbsolute(value, .{}) catch return null;
|
||||
defer dir.close();
|
||||
var dir = std.Io.Dir.openDirAbsolute(b.graph.io, value, .{}) catch return null;
|
||||
defer dir.close(b.graph.io);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Check the common environment variables for the Android SDK path and look for the NDK inside it.
|
||||
inline for (.{ "ANDROID_HOME", "ANDROID_SDK_ROOT" }) |env| {
|
||||
if (std.process.getEnvVarOwned(b.allocator, env) catch null) |sdk| {
|
||||
if (b.graph.environ_map.get(env)) |sdk| {
|
||||
if (sdk.len > 0) {
|
||||
if (findLatestNDK(b, sdk)) |ndk| return ndk;
|
||||
}
|
||||
@@ -135,10 +135,9 @@ fn findNDKPath(b: *std.Build) ?[]const u8 {
|
||||
}
|
||||
|
||||
// As a fallback, we assume the most common/default SDK path based on the OS.
|
||||
const home = std.process.getEnvVarOwned(
|
||||
b.allocator,
|
||||
const home = b.graph.environ_map.get(
|
||||
if (builtin.os.tag == .windows) "LOCALAPPDATA" else "HOME",
|
||||
) catch return null;
|
||||
) orelse return null;
|
||||
|
||||
const default_sdk_path = b.pathJoin(
|
||||
&.{
|
||||
@@ -157,8 +156,8 @@ fn findNDKPath(b: *std.Build) ?[]const u8 {
|
||||
|
||||
fn findLatestNDK(b: *std.Build, sdk_path: []const u8) ?[]const u8 {
|
||||
const ndk_dir = b.pathJoin(&.{ sdk_path, "ndk" });
|
||||
var dir = std.fs.openDirAbsolute(ndk_dir, .{ .iterate = true }) catch return null;
|
||||
defer dir.close();
|
||||
var dir = std.Io.Dir.openDirAbsolute(b.graph.io, ndk_dir, .{ .iterate = true }) catch return null;
|
||||
defer dir.close(b.graph.io);
|
||||
|
||||
var latest_: ?struct {
|
||||
name: []const u8,
|
||||
@@ -166,7 +165,7 @@ fn findLatestNDK(b: *std.Build, sdk_path: []const u8) ?[]const u8 {
|
||||
} = null;
|
||||
var iterator = dir.iterate();
|
||||
|
||||
while (iterator.next() catch null) |file| {
|
||||
while (iterator.next(b.graph.io) catch null) |file| {
|
||||
if (file.kind != .directory) continue;
|
||||
const version = std.SemanticVersion.parse(file.name) catch continue;
|
||||
if (latest_) |latest| {
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
// The cache. This always uses b.allocator and never frees memory
|
||||
// (which is idiomatic for a Zig build exe). We cache the libc txt
|
||||
// file we create because it is expensive to generate (subprocesses).
|
||||
pub const Cache = struct {
|
||||
const Key = struct {
|
||||
arch: std.Target.Cpu.Arch,
|
||||
os: std.Target.Os.Tag,
|
||||
abi: std.Target.Abi,
|
||||
};
|
||||
|
||||
pub const Value = union(enum) {
|
||||
native: struct {
|
||||
libc: std.Build.LazyPath,
|
||||
framework: []const u8,
|
||||
system_include: []const u8,
|
||||
library: []const u8,
|
||||
},
|
||||
cross: struct {
|
||||
libc: std.Build.LazyPath,
|
||||
},
|
||||
};
|
||||
|
||||
var map: std.AutoHashMapUnmanaged(Key, ?Value) = .{};
|
||||
};
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
@@ -8,40 +33,11 @@ pub fn build(b: *std.Build) !void {
|
||||
_ = optimize;
|
||||
}
|
||||
|
||||
/// Setup the step to point to the proper Apple SDK for libc and
|
||||
/// Fetch or load the paths for the proper Apple SDK for libc and
|
||||
/// frameworks. When running on a Darwin host, this uses the native
|
||||
/// SDK installed on the system via `xcrun`. When cross-compiling from
|
||||
/// a non-Darwin host, it falls back to Zig's bundled Darwin headers.
|
||||
pub fn addPaths(
|
||||
b: *std.Build,
|
||||
step: *std.Build.Step.Compile,
|
||||
) !void {
|
||||
// The cache. This always uses b.allocator and never frees memory
|
||||
// (which is idiomatic for a Zig build exe). We cache the libc txt
|
||||
// file we create because it is expensive to generate (subprocesses).
|
||||
const Cache = struct {
|
||||
const Key = struct {
|
||||
arch: std.Target.Cpu.Arch,
|
||||
os: std.Target.Os.Tag,
|
||||
abi: std.Target.Abi,
|
||||
};
|
||||
|
||||
const Value = union(enum) {
|
||||
native: struct {
|
||||
libc: std.Build.LazyPath,
|
||||
framework: []const u8,
|
||||
system_include: []const u8,
|
||||
library: []const u8,
|
||||
},
|
||||
cross: struct {
|
||||
libc: std.Build.LazyPath,
|
||||
},
|
||||
};
|
||||
|
||||
var map: std.AutoHashMapUnmanaged(Key, ?Value) = .{};
|
||||
};
|
||||
|
||||
const target = step.rootModuleTarget();
|
||||
pub fn pathsForTarget(b: *std.Build, target: std.Target) !Cache.Value {
|
||||
const gop = try Cache.map.getOrPut(b.allocator, .{
|
||||
.arch = target.cpu.arch,
|
||||
.os = target.os.tag,
|
||||
@@ -53,14 +49,18 @@ pub fn addPaths(
|
||||
// Detect our SDK using the "findNative" Zig stdlib function.
|
||||
// This is really important because it forces using `xcrun` to
|
||||
// find the SDK path.
|
||||
const libc = std.zig.LibCInstallation.findNative(.{
|
||||
.allocator = b.allocator,
|
||||
.target = &step.rootModuleTarget(),
|
||||
.verbose = false,
|
||||
}) catch break :darwin;
|
||||
const libc = std.zig.LibCInstallation.findNative(
|
||||
b.allocator,
|
||||
b.graph.io,
|
||||
.{
|
||||
.environ_map = &b.graph.environ_map,
|
||||
.target = &target,
|
||||
.verbose = false,
|
||||
},
|
||||
) catch break :darwin;
|
||||
|
||||
// Render the file compatible with the `--libc` Zig flag.
|
||||
var stream: std.io.Writer.Allocating = .init(b.allocator);
|
||||
var stream: std.Io.Writer.Allocating = .init(b.allocator);
|
||||
defer stream.deinit();
|
||||
try libc.render(&stream.writer);
|
||||
|
||||
@@ -112,7 +112,7 @@ pub fn addPaths(
|
||||
// Fall back to Zig's bundled Darwin headers for libc resolution.
|
||||
const zig_lib_path = b.graph.zig_lib_directory.path.?;
|
||||
const include_dir = b.pathJoin(&.{
|
||||
zig_lib_path, "libc", "include", "any-macos-any",
|
||||
zig_lib_path, "libc", "include", "any-darwin-any",
|
||||
});
|
||||
|
||||
const wf = b.addWriteFiles();
|
||||
@@ -129,7 +129,7 @@ pub fn addPaths(
|
||||
gop.value_ptr.* = .{ .cross = .{ .libc = path } };
|
||||
}
|
||||
|
||||
const value = gop.value_ptr.* orelse return switch (target.os.tag) {
|
||||
return gop.value_ptr.* orelse return switch (target.os.tag) {
|
||||
// Return a more descriptive error. Before we just returned the
|
||||
// generic error but this was confusing a lot of community members.
|
||||
// It costs us nothing in the build script to return something better.
|
||||
@@ -139,8 +139,18 @@ pub fn addPaths(
|
||||
.watchos => error.XcodeWatchOSSDKNotFound,
|
||||
else => error.XcodeAppleSDKNotFound,
|
||||
};
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
/// Setup the step to point to the proper Apple SDK for libc and
|
||||
/// frameworks. When running on a Darwin host, this uses the native
|
||||
/// SDK installed on the system via `xcrun`. When cross-compiling from
|
||||
/// a non-Darwin host, it falls back to Zig's bundled Darwin headers.
|
||||
pub fn addPaths(
|
||||
b: *std.Build,
|
||||
step: *std.Build.Step.Compile,
|
||||
) !void {
|
||||
const target = step.rootModuleTarget();
|
||||
switch (try pathsForTarget(b, target)) {
|
||||
.native => |native| {
|
||||
step.setLibCFile(native.libc);
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libcpp = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibCpp();
|
||||
lib.addIncludePath(b.path("vendor"));
|
||||
lib.root_module.addIncludePath(b.path("vendor"));
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
@@ -23,20 +23,20 @@ pub fn build(b: *std.Build) !void {
|
||||
defer flags.deinit(b.allocator);
|
||||
|
||||
if (b.lazyDependency("breakpad", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path("src"));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addIncludePath(upstream.path("src"));
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = common,
|
||||
.flags = flags.items,
|
||||
});
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = common_apple,
|
||||
.flags = flags.items,
|
||||
});
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = client_apple,
|
||||
.flags = flags.items,
|
||||
@@ -44,19 +44,19 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
switch (target.result.os.tag) {
|
||||
.macos => {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = common_mac,
|
||||
.flags = flags.items,
|
||||
});
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = client_mac,
|
||||
.flags = flags.items,
|
||||
});
|
||||
},
|
||||
|
||||
.ios => lib.addCSourceFiles(.{
|
||||
.ios => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = client_ios,
|
||||
.flags = flags.items,
|
||||
@@ -67,12 +67,12 @@ pub fn build(b: *std.Build) !void {
|
||||
}
|
||||
|
||||
if (target.result.os.tag == .linux) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = common_linux,
|
||||
.flags = flags.items,
|
||||
});
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = client_linux,
|
||||
.flags = flags.items,
|
||||
|
||||
@@ -22,18 +22,16 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime
|
||||
// headers. The MSVC SDK include directories (added via linkLibC)
|
||||
// contain both C and C++ headers, so linkLibCpp is not needed.
|
||||
.link_libcpp = target.result.abi != .msvc,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime headers.
|
||||
// The MSVC SDK include directories (added via linkLibC) contain
|
||||
// both C and C++ headers, so linkLibCpp is not needed.
|
||||
if (target.result.abi != .msvc) {
|
||||
lib.linkLibCpp();
|
||||
}
|
||||
b.installArtifact(lib);
|
||||
|
||||
// Zig module
|
||||
@@ -87,8 +85,8 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Add the core Dear Imgui source files
|
||||
if (b.lazyDependency("imgui", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"imgui_demo.cpp",
|
||||
@@ -107,20 +105,20 @@ pub fn build(b: *std.Build) !void {
|
||||
);
|
||||
|
||||
if (freetype) {
|
||||
lib.addCSourceFile(.{
|
||||
lib.root_module.addCSourceFile(.{
|
||||
.file = upstream.path("misc/freetype/imgui_freetype.cpp"),
|
||||
.flags = flags.items,
|
||||
});
|
||||
|
||||
if (b.systemIntegrationOption("freetype", .{})) {
|
||||
lib.linkSystemLibrary2("freetype2", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("freetype2", dynamic_link_opts);
|
||||
} else {
|
||||
const freetype_dep = b.dependency("freetype", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.@"enable-libpng" = true,
|
||||
});
|
||||
lib.linkLibrary(freetype_dep.artifact("freetype"));
|
||||
lib.root_module.linkLibrary(freetype_dep.artifact("freetype"));
|
||||
if (freetype_dep.builder.lazyDependency(
|
||||
"freetype",
|
||||
.{},
|
||||
@@ -131,7 +129,7 @@ pub fn build(b: *std.Build) !void {
|
||||
}
|
||||
|
||||
if (backend_metal) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path("backends"),
|
||||
.files = &.{"imgui_impl_metal.mm"},
|
||||
.flags = flags.items,
|
||||
@@ -143,7 +141,7 @@ pub fn build(b: *std.Build) !void {
|
||||
);
|
||||
}
|
||||
if (backend_osx) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path("backends"),
|
||||
.files = &.{"imgui_impl_osx.mm"},
|
||||
.flags = flags.items,
|
||||
@@ -155,7 +153,7 @@ pub fn build(b: *std.Build) !void {
|
||||
);
|
||||
}
|
||||
if (backend_opengl3) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path("backends"),
|
||||
.files = &.{"imgui_impl_opengl3.cpp"},
|
||||
.flags = flags.items,
|
||||
@@ -170,8 +168,8 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Add the C bindings
|
||||
if (b.lazyDependency("bindings", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"dcimgui.cpp",
|
||||
@@ -179,7 +177,7 @@ pub fn build(b: *std.Build) !void {
|
||||
},
|
||||
.flags = flags.items,
|
||||
});
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = b.path(""),
|
||||
.files = &.{"ext.cpp"},
|
||||
.flags = flags.items,
|
||||
@@ -201,7 +199,7 @@ pub fn build(b: *std.Build) !void {
|
||||
}),
|
||||
});
|
||||
test_exe.root_module.addOptions("build_options", options);
|
||||
test_exe.linkLibrary(lib);
|
||||
test_exe.root_module.linkLibrary(lib);
|
||||
const tests_run = b.addRunArtifact(test_exe);
|
||||
const test_step = b.step("test", "Run tests");
|
||||
test_step.dependOn(&tests_run.step);
|
||||
|
||||
@@ -41,7 +41,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
if (b.systemIntegrationOption("fontconfig", .{})) {
|
||||
module.linkSystemLibrary("fontconfig", dynamic_link_opts);
|
||||
test_exe.linkSystemLibrary2("fontconfig", dynamic_link_opts);
|
||||
test_exe.root_module.linkSystemLibrary("fontconfig", dynamic_link_opts);
|
||||
} else {
|
||||
const lib = try buildLib(b, module, .{
|
||||
.target = target,
|
||||
@@ -54,7 +54,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.dynamic_link_opts = dynamic_link_opts,
|
||||
});
|
||||
|
||||
test_exe.linkLibrary(lib);
|
||||
test_exe.root_module.linkLibrary(lib);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,15 +71,18 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
|
||||
const dynamic_link_opts = options.dynamic_link_opts;
|
||||
|
||||
if (target.result.os.tag != .windows) {
|
||||
lib.linkSystemLibrary("pthread");
|
||||
lib.root_module.linkSystemLibrary("pthread", dynamic_link_opts);
|
||||
}
|
||||
|
||||
lib.addIncludePath(b.path("override/include"));
|
||||
lib.root_module.addIncludePath(b.path("override/include"));
|
||||
module.addIncludePath(b.path("override/include"));
|
||||
|
||||
var flags: std.ArrayList([]const u8) = .empty;
|
||||
@@ -194,19 +197,17 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
}
|
||||
}
|
||||
|
||||
const dynamic_link_opts = options.dynamic_link_opts;
|
||||
|
||||
// Freetype2
|
||||
_ = b.systemIntegrationOption("freetype", .{}); // So it shows up in help
|
||||
if (freetype_enabled) {
|
||||
if (b.systemIntegrationOption("freetype", .{})) {
|
||||
lib.linkSystemLibrary2("freetype2", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("freetype2", dynamic_link_opts);
|
||||
} else {
|
||||
if (b.lazyDependency(
|
||||
"freetype",
|
||||
.{ .target = target, .optimize = optimize },
|
||||
)) |freetype_dep| {
|
||||
lib.linkLibrary(freetype_dep.artifact("freetype"));
|
||||
lib.root_module.linkLibrary(freetype_dep.artifact("freetype"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,22 +228,22 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
}
|
||||
|
||||
if (b.systemIntegrationOption("libxml2", .{})) {
|
||||
lib.linkSystemLibrary2("libxml-2.0", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("libxml-2.0", dynamic_link_opts);
|
||||
} else {
|
||||
if (b.lazyDependency("libxml2", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.iconv = libxml2_iconv_enabled,
|
||||
})) |libxml2_dep| {
|
||||
lib.linkLibrary(libxml2_dep.artifact("xml2"));
|
||||
lib.root_module.linkLibrary(libxml2_dep.artifact("xml2"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (b.lazyDependency("fontconfig", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addIncludePath(upstream.path(""));
|
||||
module.addIncludePath(upstream.path(""));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = srcs,
|
||||
.flags = flags.items,
|
||||
|
||||
@@ -39,7 +39,7 @@ pub fn build(b: *std.Build) !void {
|
||||
if (b.systemIntegrationOption("freetype", .{})) {
|
||||
module.linkSystemLibrary("freetype2", dynamic_link_opts);
|
||||
if (test_exe) |exe| {
|
||||
exe.linkSystemLibrary2("freetype2", dynamic_link_opts);
|
||||
exe.root_module.linkSystemLibrary("freetype2", dynamic_link_opts);
|
||||
}
|
||||
} else {
|
||||
const lib = try buildLib(b, module, .{
|
||||
@@ -52,7 +52,7 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
|
||||
if (test_exe) |exe| {
|
||||
exe.linkLibrary(lib);
|
||||
exe.root_module.linkLibrary(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,10 +68,10 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
@@ -101,10 +101,10 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
|
||||
// Zlib
|
||||
if (b.systemIntegrationOption("zlib", .{})) {
|
||||
lib.linkSystemLibrary2("zlib", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("zlib", dynamic_link_opts);
|
||||
} else {
|
||||
const zlib_dep = b.dependency("zlib", .{ .target = target, .optimize = optimize });
|
||||
lib.linkLibrary(zlib_dep.artifact("z"));
|
||||
lib.root_module.linkLibrary(zlib_dep.artifact("z"));
|
||||
}
|
||||
|
||||
// Libpng
|
||||
@@ -113,50 +113,50 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
try flags.append(b.allocator, "-DFT_CONFIG_OPTION_USE_PNG=1");
|
||||
|
||||
if (b.systemIntegrationOption("libpng", .{})) {
|
||||
lib.linkSystemLibrary2("libpng", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("libpng", dynamic_link_opts);
|
||||
} else {
|
||||
const libpng_dep = b.dependency(
|
||||
"libpng",
|
||||
.{ .target = target, .optimize = optimize },
|
||||
);
|
||||
lib.linkLibrary(libpng_dep.artifact("png"));
|
||||
lib.root_module.linkLibrary(libpng_dep.artifact("png"));
|
||||
}
|
||||
}
|
||||
|
||||
if (b.lazyDependency("freetype", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path("include"));
|
||||
lib.root_module.addIncludePath(upstream.path("include"));
|
||||
module.addIncludePath(upstream.path("include"));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = srcs,
|
||||
.flags = flags.items,
|
||||
});
|
||||
|
||||
switch (target.result.os.tag) {
|
||||
.linux => lib.addCSourceFile(.{
|
||||
.linux => lib.root_module.addCSourceFile(.{
|
||||
.file = upstream.path("builds/unix/ftsystem.c"),
|
||||
.flags = flags.items,
|
||||
}),
|
||||
.windows => lib.addCSourceFile(.{
|
||||
.windows => lib.root_module.addCSourceFile(.{
|
||||
.file = upstream.path("builds/windows/ftsystem.c"),
|
||||
.flags = flags.items,
|
||||
}),
|
||||
else => lib.addCSourceFile(.{
|
||||
else => lib.root_module.addCSourceFile(.{
|
||||
.file = upstream.path("src/base/ftsystem.c"),
|
||||
.flags = flags.items,
|
||||
}),
|
||||
}
|
||||
switch (target.result.os.tag) {
|
||||
.windows => {
|
||||
lib.addCSourceFile(.{
|
||||
lib.root_module.addCSourceFile(.{
|
||||
.file = upstream.path("builds/windows/ftdebug.c"),
|
||||
.flags = flags.items,
|
||||
});
|
||||
lib.addWin32ResourceFile(.{
|
||||
lib.root_module.addWin32ResourceFile(.{
|
||||
.file = upstream.path("src/base/ftver.rc"),
|
||||
});
|
||||
},
|
||||
else => lib.addCSourceFile(.{
|
||||
else => lib.root_module.addCSourceFile(.{
|
||||
.file = upstream.path("src/base/ftdebug.c"),
|
||||
.flags = flags.items,
|
||||
}),
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.optimize = optimize,
|
||||
}),
|
||||
});
|
||||
test_exe.linkLibrary(lib);
|
||||
test_exe.root_module.linkLibrary(lib);
|
||||
const tests_run = b.addRunArtifact(test_exe);
|
||||
const test_step = b.step("test", "Run tests");
|
||||
test_step.dependOn(&tests_run.step);
|
||||
@@ -47,20 +47,18 @@ fn buildGlslang(
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime
|
||||
// headers. The MSVC SDK include directories (added via linkLibC)
|
||||
// contain both C and C++ headers, so linkLibCpp is not needed.
|
||||
.link_libcpp = target.result.abi != .msvc,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime headers.
|
||||
// The MSVC SDK include directories (added via linkLibC) contain
|
||||
// both C and C++ headers, so linkLibCpp is not needed.
|
||||
if (target.result.abi != .msvc) {
|
||||
lib.linkLibCpp();
|
||||
}
|
||||
if (upstream_) |upstream| lib.addIncludePath(upstream.path(""));
|
||||
lib.addIncludePath(b.path("override"));
|
||||
if (upstream_) |upstream| lib.root_module.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addIncludePath(b.path("override"));
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
@@ -82,7 +80,7 @@ fn buildGlslang(
|
||||
}
|
||||
|
||||
if (upstream_) |upstream| {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.flags = flags.items,
|
||||
.files = &.{
|
||||
@@ -141,7 +139,7 @@ fn buildGlslang(
|
||||
});
|
||||
|
||||
if (target.result.os.tag != .windows) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.flags = flags.items,
|
||||
.files = &.{
|
||||
@@ -149,7 +147,7 @@ fn buildGlslang(
|
||||
},
|
||||
});
|
||||
} else {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.flags = flags.items,
|
||||
.files = &.{
|
||||
|
||||
@@ -17,12 +17,32 @@ pub fn build(b: *std.Build) !void {
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
// Needs the gtk.h header
|
||||
module.linkSystemLibrary("gtk4", dynamic_link_opts);
|
||||
|
||||
if (b.systemIntegrationOption("gtk4-layer-shell", .{})) {
|
||||
module.linkSystemLibrary("gtk4-layer-shell-0", dynamic_link_opts);
|
||||
} else {
|
||||
translate: {
|
||||
const translate_c = b.lazyImport(@This(), "translate_c") orelse break :translate;
|
||||
const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse break :translate;
|
||||
const Translator = translate_c.Translator;
|
||||
|
||||
const link_system_libs_full: [2]Translator.LinkSystemLib = .{
|
||||
.{ .name = "gtk4", .options = dynamic_link_opts },
|
||||
.{ .name = "gtk4-layer-shell-0", .options = dynamic_link_opts },
|
||||
};
|
||||
|
||||
const headers = Translator.init(translate_c_dep, .{
|
||||
.c_source_file = b.addWriteFiles().add("c.h",
|
||||
\\#include <gtk4-layer-shell.h>
|
||||
),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_system_libs = if (b.systemIntegrationOption("gtk4-layer-shell", .{}))
|
||||
&link_system_libs_full
|
||||
else
|
||||
link_system_libs_full[0..1],
|
||||
});
|
||||
module.addImport("c", headers.mod);
|
||||
}
|
||||
|
||||
if (!b.systemIntegrationOption("gtk4-layer-shell", .{})) {
|
||||
_ = try buildLib(b, module, .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
@@ -42,6 +62,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
});
|
||||
b.installArtifact(lib);
|
||||
@@ -52,13 +73,12 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
const upstream = upstream_ orelse return lib;
|
||||
const wayland_protocols = wayland_protocols_ orelse return lib;
|
||||
|
||||
lib.linkLibC();
|
||||
lib.addIncludePath(upstream.path("include"));
|
||||
lib.addIncludePath(upstream.path("src"));
|
||||
lib.root_module.addIncludePath(upstream.path("include"));
|
||||
lib.root_module.addIncludePath(upstream.path("src"));
|
||||
module.addIncludePath(upstream.path("include"));
|
||||
|
||||
// GTK
|
||||
lib.linkSystemLibrary2("gtk4", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("gtk4", dynamic_link_opts);
|
||||
|
||||
// Wayland headers and source files
|
||||
{
|
||||
@@ -92,9 +112,9 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
const source_scanner = b.addSystemCommand(&.{ "wayland-scanner", "private-code" });
|
||||
source_scanner.addFileArg(xml);
|
||||
const source = source_scanner.addOutputFileArg(b.fmt("{s}.c", .{name}));
|
||||
lib.addCSourceFile(.{ .file = source });
|
||||
lib.root_module.addCSourceFile(.{ .file = source });
|
||||
}
|
||||
lib.addIncludePath(wf.getDirectory());
|
||||
lib.root_module.addIncludePath(wf.getDirectory());
|
||||
}
|
||||
|
||||
lib.installHeadersDirectory(
|
||||
@@ -113,7 +133,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
"stubbed-surface.c",
|
||||
"xdg-surface-server.c",
|
||||
};
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path("src"),
|
||||
.files = srcs,
|
||||
.flags = &.{
|
||||
|
||||
@@ -14,5 +14,10 @@
|
||||
.hash = "N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
|
||||
.lazy = true,
|
||||
},
|
||||
.translate_c = .{
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
.lazy = true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @cImport({
|
||||
@cInclude("gtk4-layer-shell.h");
|
||||
});
|
||||
const c = @import("c");
|
||||
const gdk = @import("gdk");
|
||||
const gtk = @import("gtk");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
const Error = @import("errors.zig").Error;
|
||||
|
||||
/// Data type holding the memory modes available to client programs.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
const common = @import("common.zig");
|
||||
const Error = @import("errors.zig").Error;
|
||||
const Direction = common.Direction;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const std = @import("std");
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
|
||||
const root_build_container = @This();
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
@@ -8,31 +10,6 @@ pub fn build(b: *std.Build) !void {
|
||||
const coretext_enabled = b.option(bool, "enable-coretext", "Build coretext") orelse false;
|
||||
const freetype_enabled = b.option(bool, "enable-freetype", "Build freetype") orelse true;
|
||||
|
||||
const freetype = b.dependency("freetype", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.@"enable-libpng" = true,
|
||||
});
|
||||
const macos = b.dependency("macos", .{ .target = target, .optimize = optimize });
|
||||
|
||||
const module = harfbuzz: {
|
||||
const module = b.addModule("harfbuzz", .{
|
||||
.root_source_file = b.path("main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.imports = &.{
|
||||
.{ .name = "freetype", .module = freetype.module("freetype") },
|
||||
.{ .name = "macos", .module = macos.module("macos") },
|
||||
},
|
||||
});
|
||||
|
||||
const options = b.addOptions();
|
||||
options.addOption(bool, "coretext", coretext_enabled);
|
||||
options.addOption(bool, "freetype", freetype_enabled);
|
||||
module.addOptions("build_options", options);
|
||||
break :harfbuzz module;
|
||||
};
|
||||
|
||||
// For dynamic linking, we prefer dynamic linking and to search by
|
||||
// mode first. Mode first will search all paths for a dynamic library
|
||||
// before falling back to static.
|
||||
@@ -41,33 +18,63 @@ pub fn build(b: *std.Build) !void {
|
||||
.search_strategy = .mode_first,
|
||||
};
|
||||
|
||||
const test_exe = b.addTest(.{
|
||||
.name = "test",
|
||||
.root_module = b.createModule(.{
|
||||
const freetype = b.dependency("freetype", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.@"enable-libpng" = true,
|
||||
});
|
||||
|
||||
const module = harfbuzz: {
|
||||
const module = b.addModule("harfbuzz", .{
|
||||
.root_source_file = b.path("main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
.imports = if (target.result.os.tag.isDarwin())
|
||||
&.{
|
||||
.{ .name = "freetype", .module = freetype.module("freetype") },
|
||||
.{
|
||||
.name = "macos",
|
||||
.module = b.dependency("macos", .{ .target = target, .optimize = optimize })
|
||||
.module("macos"),
|
||||
},
|
||||
}
|
||||
else
|
||||
&.{
|
||||
.{ .name = "freetype", .module = freetype.module("freetype") },
|
||||
},
|
||||
});
|
||||
|
||||
try HarfBuzzC.addImportToModule(b, module, .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.harfbuzz = if (b.systemIntegrationOption("harfbuzz", .{})) .{ .dynamic = dynamic_link_opts } else .static,
|
||||
.coretext = coretext_enabled,
|
||||
.freetype = if (freetype_enabled) ft: {
|
||||
break :ft if (b.systemIntegrationOption("freetype", .{}))
|
||||
.{ .dynamic = dynamic_link_opts }
|
||||
else
|
||||
.static;
|
||||
} else null,
|
||||
});
|
||||
|
||||
const options = b.addOptions();
|
||||
options.addOption(bool, "coretext", coretext_enabled);
|
||||
options.addOption(bool, "freetype", freetype_enabled);
|
||||
module.addOptions("build_options", options);
|
||||
break :harfbuzz module;
|
||||
};
|
||||
|
||||
const test_exe = b.addTest(.{
|
||||
.name = "test",
|
||||
.root_module = module,
|
||||
});
|
||||
|
||||
{
|
||||
var it = module.import_table.iterator();
|
||||
while (it.next()) |entry| test_exe.root_module.addImport(entry.key_ptr.*, entry.value_ptr.*);
|
||||
if (b.systemIntegrationOption("freetype", .{})) {
|
||||
test_exe.linkSystemLibrary2("freetype2", dynamic_link_opts);
|
||||
} else {
|
||||
test_exe.linkLibrary(freetype.artifact("freetype"));
|
||||
}
|
||||
const tests_run = b.addRunArtifact(test_exe);
|
||||
const test_step = b.step("test", "Run tests");
|
||||
test_step.dependOn(&tests_run.step);
|
||||
}
|
||||
const tests_run = b.addRunArtifact(test_exe);
|
||||
const test_step = b.step("test", "Run tests");
|
||||
test_step.dependOn(&tests_run.step);
|
||||
|
||||
if (b.systemIntegrationOption("harfbuzz", .{})) {
|
||||
module.linkSystemLibrary("harfbuzz", dynamic_link_opts);
|
||||
test_exe.linkSystemLibrary2("harfbuzz", dynamic_link_opts);
|
||||
} else {
|
||||
const lib = try buildLib(b, module, .{
|
||||
if (!b.systemIntegrationOption("harfbuzz", .{})) {
|
||||
const lib = try buildLib(b, .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
|
||||
@@ -77,11 +84,11 @@ pub fn build(b: *std.Build) !void {
|
||||
.dynamic_link_opts = dynamic_link_opts,
|
||||
});
|
||||
|
||||
test_exe.linkLibrary(lib);
|
||||
test_exe.root_module.linkLibrary(lib);
|
||||
}
|
||||
}
|
||||
|
||||
fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Build.Step.Compile {
|
||||
fn buildLib(b: *std.Build, options: anytype) !*std.Build.Step.Compile {
|
||||
const target = options.target;
|
||||
const optimize = options.optimize;
|
||||
|
||||
@@ -99,18 +106,16 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime
|
||||
// headers. The MSVC SDK include directories (added via linkLibC)
|
||||
// contain both C and C++ headers, so linkLibCpp is not needed.
|
||||
.link_libcpp = target.result.abi != .msvc,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime headers.
|
||||
// The MSVC SDK include directories (added via linkLibC) contain
|
||||
// both C and C++ headers, so linkLibCpp is not needed.
|
||||
if (target.result.abi != .msvc) {
|
||||
lib.linkLibCpp();
|
||||
}
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
@@ -154,30 +159,20 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
});
|
||||
|
||||
if (b.systemIntegrationOption("freetype", .{})) {
|
||||
lib.linkSystemLibrary2("freetype2", dynamic_link_opts);
|
||||
module.linkSystemLibrary("freetype2", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("freetype2", dynamic_link_opts);
|
||||
} else {
|
||||
lib.linkLibrary(freetype.artifact("freetype"));
|
||||
|
||||
if (freetype.builder.lazyDependency(
|
||||
"freetype",
|
||||
.{},
|
||||
)) |freetype_dep| {
|
||||
module.addIncludePath(freetype_dep.path("include"));
|
||||
}
|
||||
lib.root_module.linkLibrary(freetype.artifact("freetype"));
|
||||
}
|
||||
}
|
||||
|
||||
if (coretext_enabled) {
|
||||
try flags.appendSlice(b.allocator, &.{"-DHAVE_CORETEXT=1"});
|
||||
lib.linkFramework("CoreText");
|
||||
module.linkFramework("CoreText", .{});
|
||||
lib.root_module.linkFramework("CoreText", .{});
|
||||
}
|
||||
|
||||
if (b.lazyDependency("harfbuzz", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path("src"));
|
||||
module.addIncludePath(upstream.path("src"));
|
||||
lib.addCSourceFile(.{
|
||||
lib.root_module.addIncludePath(upstream.path("src"));
|
||||
lib.root_module.addCSourceFile(.{
|
||||
.file = upstream.path("src/harfbuzz.cc"),
|
||||
.flags = flags.items,
|
||||
});
|
||||
@@ -192,3 +187,173 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
const HarfBuzzC = struct {
|
||||
const AddImportToModuleOptions = struct {
|
||||
const LinkMode = union(enum) {
|
||||
static,
|
||||
dynamic: std.Build.Module.LinkSystemLibraryOptions,
|
||||
};
|
||||
|
||||
target: std.Build.ResolvedTarget,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
harfbuzz: LinkMode,
|
||||
coretext: bool,
|
||||
freetype: ?LinkMode,
|
||||
};
|
||||
|
||||
fn fmtInclude(w: *std.Io.Writer, name: []const u8, mode: AddImportToModuleOptions.LinkMode) !void {
|
||||
if (mode == .dynamic) {
|
||||
try w.print("#include <{s}>\n", .{name});
|
||||
} else {
|
||||
try w.print("#include \"{s}\"\n", .{name});
|
||||
}
|
||||
}
|
||||
|
||||
fn addImportToModule(
|
||||
b: *std.Build,
|
||||
module: *std.Build.Module,
|
||||
options: AddImportToModuleOptions,
|
||||
) !void {
|
||||
// TODO: There's a decent amount of duplication here right now.
|
||||
// Basically we want to mirror what we're passing in buildLib to make
|
||||
// sure that the translation is generated as correct as possible.
|
||||
// Eventually, we want to try and unravel this as much as we can, to
|
||||
// the point that ultimately all C flags and even link options are
|
||||
// self-contained in the translation artifact.
|
||||
//
|
||||
// This is a bit tricky right now as there are situations where we
|
||||
// provide a static library built straight off of the C file, hence the
|
||||
// duplication.
|
||||
//
|
||||
// NOTE: This function de-allocates nothing as b.allocator is an arena
|
||||
// (unfortunately not documented, but a cursory search in various
|
||||
// communities or the issue trackers should turn up confirmation).
|
||||
|
||||
const translate_c = b.lazyImport(root_build_container, "translate_c") orelse return;
|
||||
const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse return;
|
||||
|
||||
const c_source = c_source: {
|
||||
var source_builder: std.Io.Writer.Allocating = .init(b.allocator);
|
||||
try fmtInclude(&source_builder.writer, "hb.h", options.harfbuzz);
|
||||
|
||||
if (options.coretext) {
|
||||
try fmtInclude(&source_builder.writer, "hb-coretext.h", options.harfbuzz);
|
||||
}
|
||||
|
||||
if (options.freetype != null) {
|
||||
try fmtInclude(&source_builder.writer, "hb-ft.h", options.harfbuzz);
|
||||
}
|
||||
|
||||
break :c_source source_builder.written();
|
||||
};
|
||||
|
||||
// Assemble system libs
|
||||
const system_libs = libs: {
|
||||
var libs_builder: std.ArrayList(translate_c.Translator.LinkSystemLib) = .empty;
|
||||
if (options.harfbuzz == .dynamic)
|
||||
try libs_builder.append(b.allocator, .{ .name = "harfbuzz", .options = options.harfbuzz.dynamic });
|
||||
if (options.freetype) |ft| {
|
||||
if (ft == .dynamic)
|
||||
try libs_builder.append(b.allocator, .{ .name = "freetype2", .options = ft.dynamic });
|
||||
}
|
||||
|
||||
break :libs libs_builder.items;
|
||||
};
|
||||
|
||||
// Assemble flags
|
||||
const flags = flags: {
|
||||
var flag_builder: std.ArrayList([]const u8) = .empty;
|
||||
try flag_builder.appendSlice(b.allocator, &.{
|
||||
"-DHAVE_STDBOOL_H",
|
||||
});
|
||||
// Disable ubsan for MSVC: Zig's ubsan runtime cannot be bundled
|
||||
// on Windows (LNK4229), leaving __ubsan_handle_* unresolved when
|
||||
// the static archive is consumed by an external linker.
|
||||
if (options.target.result.abi == .msvc) {
|
||||
try flag_builder.appendSlice(b.allocator, &.{
|
||||
"-fno-sanitize=undefined",
|
||||
"-fno-sanitize-trap=undefined",
|
||||
});
|
||||
}
|
||||
if (options.target.result.os.tag != .windows) {
|
||||
try flag_builder.appendSlice(b.allocator, &.{
|
||||
"-DHAVE_UNISTD_H",
|
||||
"-DHAVE_SYS_MMAN_H",
|
||||
"-DHAVE_PTHREAD=1",
|
||||
});
|
||||
}
|
||||
|
||||
// Freetype flags/non-system include paths
|
||||
if (options.freetype != null) {
|
||||
try flag_builder.appendSlice(b.allocator, &.{
|
||||
"-DHAVE_FREETYPE=1",
|
||||
|
||||
// Let's just assume a new freetype
|
||||
"-DHAVE_FT_GET_VAR_BLEND_COORDINATES=1",
|
||||
"-DHAVE_FT_SET_VAR_BLEND_COORDINATES=1",
|
||||
"-DHAVE_FT_DONE_MM_VAR=1",
|
||||
"-DHAVE_FT_GET_TRANSFORM=1",
|
||||
});
|
||||
}
|
||||
|
||||
// Coretext
|
||||
if (options.coretext) {
|
||||
try flag_builder.appendSlice(b.allocator, &.{"-DHAVE_CORETEXT=1"});
|
||||
try flag_builder.appendSlice(b.allocator, &.{"-fblocks"});
|
||||
}
|
||||
|
||||
break :flags flag_builder.items;
|
||||
};
|
||||
|
||||
const hb_c: translate_c.Translator = .init(translate_c_dep, .{
|
||||
.c_source_file = b.addWriteFiles().add(
|
||||
"hb_c.h",
|
||||
c_source,
|
||||
),
|
||||
.target = options.target,
|
||||
.optimize = options.optimize,
|
||||
.link_libc = true,
|
||||
.link_system_libs = system_libs,
|
||||
.libc_file = if (options.target.result.os.tag.isDarwin()) libc_file: {
|
||||
switch (try @import("apple_sdk").pathsForTarget(b, options.target.result)) {
|
||||
inline else => |paths| break :libc_file paths.libc,
|
||||
}
|
||||
} else null,
|
||||
.extra_args = flags,
|
||||
});
|
||||
|
||||
if (options.harfbuzz == .static) {
|
||||
if (b.lazyDependency("harfbuzz", .{})) |upstream| {
|
||||
hb_c.addIncludePath(upstream.path("src"));
|
||||
}
|
||||
}
|
||||
|
||||
// Freetype non-system include paths
|
||||
if (options.freetype) |freetype_enabled| {
|
||||
if (freetype_enabled == .static) {
|
||||
const ft_dep = b.dependency("freetype", .{
|
||||
.target = options.target,
|
||||
.optimize = options.optimize,
|
||||
.@"enable-libpng" = true,
|
||||
});
|
||||
|
||||
if (ft_dep.builder.lazyDependency(
|
||||
"freetype",
|
||||
.{},
|
||||
)) |freetype_lazy_dep| {
|
||||
hb_c.addIncludePath(freetype_lazy_dep.path("include"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Coretext
|
||||
if (options.coretext) {
|
||||
// NOTE: We should not necessarily need to add this directly to C
|
||||
// translation, so we just add it to the module.
|
||||
hb_c.mod.linkFramework("CoreText", .{});
|
||||
}
|
||||
|
||||
module.addImport("hb_c", hb_c.mod);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
.fingerprint = 0xbd60917cd18865d8,
|
||||
.paths = .{""},
|
||||
.dependencies = .{
|
||||
.translate_c = .{
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
// harfbuzz/harfbuzz
|
||||
.harfbuzz = .{
|
||||
.url = "https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz",
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
const builtin = @import("builtin");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
pub const c = @cImport({
|
||||
@cInclude("hb.h");
|
||||
if (build_options.freetype) @cInclude("hb-ft.h");
|
||||
if (build_options.coretext) @cInclude("hb-coretext.h");
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
|
||||
/// The direction of a text segment or buffer.
|
||||
///
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const macos = @import("macos");
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
const Face = @import("face.zig").Face;
|
||||
const Font = @import("font.zig").Font;
|
||||
const Error = @import("errors.zig").Error;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
|
||||
/// A font face is an object that represents a single face from within a font family.
|
||||
///
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
const Face = @import("face.zig").Face;
|
||||
const Error = @import("errors.zig").Error;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const freetype = @import("freetype");
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
const Face = @import("face.zig").Face;
|
||||
const Font = @import("font.zig").Font;
|
||||
const Error = @import("errors.zig").Error;
|
||||
|
||||
@@ -7,7 +7,7 @@ const font = @import("font.zig");
|
||||
const shapepkg = @import("shape.zig");
|
||||
const versionpkg = @import("version.zig");
|
||||
|
||||
pub const c = @import("c.zig").c;
|
||||
pub const c = @import("hb_c");
|
||||
pub const freetype = @import("freetype.zig");
|
||||
pub const coretext = @import("coretext.zig");
|
||||
pub const MemoryMode = blob.MemoryMode;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
const Font = @import("font.zig").Font;
|
||||
const Buffer = @import("buffer.zig").Buffer;
|
||||
const Feature = @import("common.zig").Feature;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("hb_c");
|
||||
|
||||
pub const Version = struct {
|
||||
major: u32,
|
||||
|
||||
@@ -18,17 +18,16 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_source_file = b.path("src/detect.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
// Our highway package is free of libc at runtime (uses no symbols)
|
||||
// but does require libc headers at compile time.
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
|
||||
// Our highway package is free of libc at runtime (uses no symbols)
|
||||
// but does require libc headers at compile time.
|
||||
lib.linkLibC();
|
||||
|
||||
lib.addIncludePath(b.path("src/cpp"));
|
||||
lib.root_module.addIncludePath(b.path("src/cpp"));
|
||||
if (upstream_) |upstream| {
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addIncludePath(upstream.path(""));
|
||||
module.addIncludePath(upstream.path(""));
|
||||
}
|
||||
|
||||
@@ -102,7 +101,7 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
}
|
||||
|
||||
lib.addCSourceFiles(.{ .flags = flags.items, .files = &.{
|
||||
lib.root_module.addCSourceFiles(.{ .flags = flags.items, .files = &.{
|
||||
"src/cpp/abort.cc",
|
||||
"src/cpp/per_target.cc",
|
||||
"src/cpp/targets.cpp",
|
||||
@@ -127,7 +126,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.optimize = optimize,
|
||||
}),
|
||||
});
|
||||
test_exe.linkLibrary(lib);
|
||||
test_exe.root_module.linkLibrary(lib);
|
||||
|
||||
var it = module.import_table.iterator();
|
||||
while (it.next()) |entry| test_exe.root_module.addImport(entry.key_ptr.*, entry.value_ptr.*);
|
||||
|
||||
@@ -35,11 +35,11 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
lib.addIncludePath(b.path(""));
|
||||
lib.root_module.addIncludePath(b.path(""));
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
@@ -47,9 +47,9 @@ pub fn build(b: *std.Build) !void {
|
||||
}
|
||||
|
||||
if (b.lazyDependency("gettext", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path("gettext-runtime/intl"));
|
||||
lib.addIncludePath(upstream.path("gettext-runtime/intl/gnulib-lib"));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addIncludePath(upstream.path("gettext-runtime/intl"));
|
||||
lib.root_module.addIncludePath(upstream.path("gettext-runtime/intl/gnulib-lib"));
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path("gettext-runtime/intl"),
|
||||
.files = srcs,
|
||||
.flags = flags.items,
|
||||
|
||||
@@ -9,18 +9,10 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
if (target.result.os.tag == .linux) {
|
||||
lib.linkSystemLibrary("m");
|
||||
}
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
// For dynamic linking, we prefer dynamic linking and to search by
|
||||
// mode first. Mode first will search all paths for a dynamic library
|
||||
// before falling back to static.
|
||||
@@ -28,20 +20,27 @@ pub fn build(b: *std.Build) !void {
|
||||
.preferred_link_mode = .dynamic,
|
||||
.search_strategy = .mode_first,
|
||||
};
|
||||
if (target.result.os.tag == .linux) {
|
||||
lib.root_module.linkSystemLibrary("m", dynamic_link_opts);
|
||||
}
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
if (b.systemIntegrationOption("zlib", .{})) {
|
||||
lib.linkSystemLibrary2("zlib", dynamic_link_opts);
|
||||
lib.root_module.linkSystemLibrary("zlib", dynamic_link_opts);
|
||||
} else {
|
||||
if (b.lazyDependency(
|
||||
"zlib",
|
||||
.{ .target = target, .optimize = optimize },
|
||||
)) |zlib_dep| {
|
||||
lib.linkLibrary(zlib_dep.artifact("z"));
|
||||
lib.addIncludePath(b.path(""));
|
||||
lib.root_module.linkLibrary(zlib_dep.artifact("z"));
|
||||
lib.root_module.addIncludePath(b.path(""));
|
||||
}
|
||||
|
||||
if (b.lazyDependency("libpng", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addIncludePath(upstream.path(""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +60,7 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
}
|
||||
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = srcs,
|
||||
.flags = flags.items,
|
||||
|
||||
@@ -11,18 +11,25 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
|
||||
if (upstream_) |upstream| lib.addIncludePath(upstream.path("include"));
|
||||
lib.addIncludePath(b.path("override/include"));
|
||||
if (upstream_) |upstream| lib.root_module.addIncludePath(upstream.path("include"));
|
||||
lib.root_module.addIncludePath(b.path("override/include"));
|
||||
if (target.result.os.tag == .windows) {
|
||||
lib.addIncludePath(b.path("override/config/win32"));
|
||||
lib.linkSystemLibrary("ws2_32");
|
||||
lib.root_module.addIncludePath(b.path("override/config/win32"));
|
||||
// For dynamic linking, we prefer dynamic linking and to search by
|
||||
// mode first. Mode first will search all paths for a dynamic library
|
||||
// before falling back to static.
|
||||
const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
|
||||
.preferred_link_mode = .dynamic,
|
||||
.search_strategy = .mode_first,
|
||||
};
|
||||
lib.root_module.linkSystemLibrary("ws2_32", dynamic_link_opts);
|
||||
} else {
|
||||
lib.addIncludePath(b.path("override/config/posix"));
|
||||
lib.root_module.addIncludePath(b.path("override/config/posix"));
|
||||
}
|
||||
|
||||
var flags: std.ArrayList([]const u8) = .empty;
|
||||
@@ -98,7 +105,7 @@ pub fn build(b: *std.Build) !void {
|
||||
}
|
||||
|
||||
if (upstream_) |upstream| {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = srcs,
|
||||
.flags = flags.items,
|
||||
|
||||
@@ -2,6 +2,66 @@ const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
|
||||
const Framework = struct {
|
||||
const Tag = enum { all, macos };
|
||||
|
||||
tag: Tag,
|
||||
name: []const u8,
|
||||
headers: []const []const u8,
|
||||
};
|
||||
|
||||
const frameworks = [_]Framework{
|
||||
.{ .tag = .all, .name = "CoreFoundation", .headers = &.{"CoreFoundation.h"} },
|
||||
.{ .tag = .all, .name = "CoreGraphics", .headers = &.{"CoreGraphics.h"} },
|
||||
.{ .tag = .all, .name = "CoreText", .headers = &.{"CoreText.h"} },
|
||||
.{ .tag = .all, .name = "CoreVideo", .headers = &.{ "CoreVideo.h", "CVPixelBuffer.h" } },
|
||||
.{ .tag = .all, .name = "QuartzCore", .headers = &.{"CALayer.h"} },
|
||||
.{ .tag = .all, .name = "IOSurface", .headers = &.{"IOSurfaceRef.h"} },
|
||||
.{ .tag = .macos, .name = "Carbon", .headers = &.{"Carbon.h"} },
|
||||
};
|
||||
|
||||
const extra_headers = [_][]const u8{
|
||||
"dispatch/dispatch.h",
|
||||
"os/log.h",
|
||||
"os/signpost.h",
|
||||
};
|
||||
|
||||
const framework_header_fmt = "#include <{s}/{s}>\n";
|
||||
const extra_header_fmt = "#include <{s}>\n";
|
||||
|
||||
fn cSourceLen(tag: Framework.Tag) usize {
|
||||
var len: usize = 0;
|
||||
for (frameworks) |framework| {
|
||||
if (tag != .macos and framework.tag == .macos) continue;
|
||||
for (framework.headers) |h| len += std.fmt.count(framework_header_fmt, .{ framework.name, h });
|
||||
}
|
||||
for (extra_headers) |h| len += std.fmt.count(extra_header_fmt, .{h});
|
||||
return len;
|
||||
}
|
||||
|
||||
fn genCSource(comptime tag: Framework.Tag) [cSourceLen(tag):0]u8 {
|
||||
const len = cSourceLen(tag);
|
||||
var buf: [len:0]u8 = undefined;
|
||||
var writer: std.Io.Writer = .fixed(&buf);
|
||||
for (frameworks) |framework| {
|
||||
if (tag != .macos and framework.tag == .macos) continue;
|
||||
for (framework.headers) |h| writer.print(framework_header_fmt, .{ framework.name, h }) catch unreachable;
|
||||
}
|
||||
for (extra_headers) |h| writer.print(extra_header_fmt, .{h}) catch unreachable;
|
||||
buf[len] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
const c_source_macos = genCSource(.macos);
|
||||
const c_source_other = genCSource(.all);
|
||||
|
||||
fn linkFrameworks(tag: Framework.Tag, module: *std.Build.Module) !void {
|
||||
for (frameworks) |framework| {
|
||||
if (tag != .macos and framework.tag == .macos) continue;
|
||||
module.linkFramework(framework.name, .{});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
@@ -12,6 +72,29 @@ pub fn build(b: *std.Build) !void {
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
translate: {
|
||||
const translate_c = b.lazyImport(@This(), "translate_c") orelse break :translate;
|
||||
const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse break :translate;
|
||||
const macos_c: translate_c.Translator = .init(translate_c_dep, .{
|
||||
.c_source_file = b.addWriteFiles().add(
|
||||
"macos_c.h",
|
||||
if (target.result.os.tag == .macos) &c_source_macos else &c_source_other,
|
||||
),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.libc_file = if (target.result.os.tag.isDarwin()) libc_file: {
|
||||
switch (try apple_sdk.pathsForTarget(b, target.result)) {
|
||||
inline else => |paths| break :libc_file paths.libc,
|
||||
}
|
||||
} else null,
|
||||
});
|
||||
|
||||
// Blocks need to be enabled to use MacOS headers
|
||||
macos_c.run.addArg("-fblocks");
|
||||
|
||||
module.addImport("macos_c", macos_c.mod);
|
||||
}
|
||||
|
||||
const lib = b.addLibrary(.{
|
||||
.name = "macos",
|
||||
.root_module = b.createModule(.{
|
||||
@@ -21,34 +104,18 @@ pub fn build(b: *std.Build) !void {
|
||||
.linkage = .static,
|
||||
});
|
||||
|
||||
lib.addCSourceFile(.{
|
||||
lib.root_module.addCSourceFile(.{
|
||||
.file = b.path("os/zig_macos.c"),
|
||||
.flags = &.{"-std=c99"},
|
||||
});
|
||||
lib.addCSourceFile(.{
|
||||
lib.root_module.addCSourceFile(.{
|
||||
.file = b.path("text/ext.c"),
|
||||
});
|
||||
lib.linkFramework("CoreFoundation");
|
||||
lib.linkFramework("CoreGraphics");
|
||||
lib.linkFramework("CoreText");
|
||||
lib.linkFramework("CoreVideo");
|
||||
lib.linkFramework("QuartzCore");
|
||||
lib.linkFramework("IOSurface");
|
||||
if (target.result.os.tag == .macos) {
|
||||
lib.linkFramework("Carbon");
|
||||
module.linkFramework("Carbon", .{});
|
||||
}
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
module.linkFramework("CoreFoundation", .{});
|
||||
module.linkFramework("CoreGraphics", .{});
|
||||
module.linkFramework("CoreText", .{});
|
||||
module.linkFramework("CoreVideo", .{});
|
||||
module.linkFramework("QuartzCore", .{});
|
||||
module.linkFramework("IOSurface", .{});
|
||||
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
inline for (.{ lib.root_module, module }) |mod| {
|
||||
try linkFrameworks(if (target.result.os.tag == .macos) .macos else .all, mod);
|
||||
}
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
b.installArtifact(lib);
|
||||
|
||||
{
|
||||
@@ -63,7 +130,7 @@ pub fn build(b: *std.Build) !void {
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
try apple_sdk.addPaths(b, test_exe);
|
||||
}
|
||||
test_exe.linkLibrary(lib);
|
||||
test_exe.root_module.linkLibrary(lib);
|
||||
|
||||
var it = module.import_table.iterator();
|
||||
while (it.next()) |entry| {
|
||||
|
||||
@@ -5,5 +5,10 @@
|
||||
.paths = .{""},
|
||||
.dependencies = .{
|
||||
.apple_sdk = .{ .path = "../apple-sdk" },
|
||||
.translate_c = .{
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
.lazy = true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -10,25 +10,7 @@ pub const text = @import("text.zig");
|
||||
pub const video = @import("video.zig");
|
||||
pub const iosurface = @import("iosurface.zig");
|
||||
|
||||
// All of our C imports consolidated into one place. We used to
|
||||
// import them one by one in each package but Zig 0.14 has some
|
||||
// kind of issue with that I wasn't able to minimize.
|
||||
pub const c = @cImport({
|
||||
@cInclude("CoreFoundation/CoreFoundation.h");
|
||||
@cInclude("CoreGraphics/CoreGraphics.h");
|
||||
@cInclude("CoreText/CoreText.h");
|
||||
@cInclude("CoreVideo/CoreVideo.h");
|
||||
@cInclude("CoreVideo/CVPixelBuffer.h");
|
||||
@cInclude("QuartzCore/CALayer.h");
|
||||
@cInclude("IOSurface/IOSurfaceRef.h");
|
||||
@cInclude("dispatch/dispatch.h");
|
||||
@cInclude("os/log.h");
|
||||
@cInclude("os/signpost.h");
|
||||
|
||||
if (builtin.os.tag == .macos) {
|
||||
@cInclude("Carbon/Carbon.h");
|
||||
}
|
||||
});
|
||||
pub const c = @import("macos_c");
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
|
||||
@@ -41,7 +41,7 @@ pub fn build(b: *std.Build) !void {
|
||||
module.linkSystemLibrary("oniguruma", dynamic_link_opts);
|
||||
|
||||
if (test_exe) |exe| {
|
||||
exe.linkSystemLibrary2("oniguruma", dynamic_link_opts);
|
||||
exe.root_module.linkSystemLibrary("oniguruma", dynamic_link_opts);
|
||||
}
|
||||
} else {
|
||||
const lib = try buildLib(b, module, .{
|
||||
@@ -50,7 +50,7 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
|
||||
if (test_exe) |exe| {
|
||||
exe.linkLibrary(lib);
|
||||
exe.root_module.linkLibrary(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,12 +64,12 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
const t = target.result;
|
||||
const is_windows = t.os.tag == .windows;
|
||||
lib.linkLibC();
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
@@ -77,10 +77,10 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
}
|
||||
|
||||
if (b.lazyDependency("oniguruma", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path("src"));
|
||||
lib.root_module.addIncludePath(upstream.path("src"));
|
||||
module.addIncludePath(upstream.path("src"));
|
||||
|
||||
lib.addConfigHeader(b.addConfigHeader(.{
|
||||
lib.root_module.addConfigHeader(b.addConfigHeader(.{
|
||||
.style = .{ .cmake = upstream.path("src/config.h.cmake.in") },
|
||||
}, .{
|
||||
.PACKAGE = "oniguruma",
|
||||
@@ -109,7 +109,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
"-fno-sanitize-trap=undefined",
|
||||
});
|
||||
}
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.flags = flags.items,
|
||||
.files = &.{
|
||||
|
||||
@@ -17,10 +17,10 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
@@ -46,9 +46,9 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
if (b.lazyDependency("sentry", .{})) |upstream| {
|
||||
module.addIncludePath(upstream.path("include"));
|
||||
lib.addIncludePath(upstream.path("include"));
|
||||
lib.addIncludePath(upstream.path("src"));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addIncludePath(upstream.path("include"));
|
||||
lib.root_module.addIncludePath(upstream.path("src"));
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = srcs,
|
||||
.flags = flags.items,
|
||||
@@ -56,7 +56,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Linux-only
|
||||
if (target.result.os.tag == .linux) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"vendor/stb_sprintf.c",
|
||||
@@ -67,7 +67,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Symbolizer + Unwinder
|
||||
if (target.result.os.tag == .windows) {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/sentry_windows_dbghelp.c",
|
||||
@@ -78,7 +78,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.flags = flags.items,
|
||||
});
|
||||
} else {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/sentry_unix_pageallocator.c",
|
||||
@@ -92,7 +92,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Module finder
|
||||
switch (target.result.os.tag) {
|
||||
.windows => lib.addCSourceFiles(.{
|
||||
.windows => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/modulefinder/sentry_modulefinder_windows.c",
|
||||
@@ -100,7 +100,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.flags = flags.items,
|
||||
}),
|
||||
|
||||
.macos, .ios => lib.addCSourceFiles(.{
|
||||
.macos, .ios => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/modulefinder/sentry_modulefinder_apple.c",
|
||||
@@ -108,7 +108,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.flags = flags.items,
|
||||
}),
|
||||
|
||||
.linux => lib.addCSourceFiles(.{
|
||||
.linux => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/modulefinder/sentry_modulefinder_linux.c",
|
||||
@@ -126,7 +126,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Transport
|
||||
switch (transport) {
|
||||
.curl => lib.addCSourceFiles(.{
|
||||
.curl => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/transports/sentry_transport_curl.c",
|
||||
@@ -134,7 +134,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.flags = flags.items,
|
||||
}),
|
||||
|
||||
.winhttp => lib.addCSourceFiles(.{
|
||||
.winhttp => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/transports/sentry_transport_winhttp.c",
|
||||
@@ -142,7 +142,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.flags = flags.items,
|
||||
}),
|
||||
|
||||
.none => lib.addCSourceFiles(.{
|
||||
.none => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/transports/sentry_transport_none.c",
|
||||
@@ -153,7 +153,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Backend
|
||||
switch (backend) {
|
||||
.crashpad => lib.addCSourceFiles(.{
|
||||
.crashpad => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/backends/sentry_backend_crashpad.cpp",
|
||||
@@ -162,7 +162,7 @@ pub fn build(b: *std.Build) !void {
|
||||
}),
|
||||
|
||||
.breakpad => {
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/backends/sentry_backend_breakpad.cpp",
|
||||
@@ -174,15 +174,15 @@ pub fn build(b: *std.Build) !void {
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
})) |breakpad_dep| {
|
||||
lib.linkLibrary(breakpad_dep.artifact("breakpad"));
|
||||
lib.root_module.linkLibrary(breakpad_dep.artifact("breakpad"));
|
||||
|
||||
// We need to add this because Sentry includes some breakpad
|
||||
// headers that include this vendored file...
|
||||
lib.addIncludePath(breakpad_dep.path("vendor"));
|
||||
lib.root_module.addIncludePath(breakpad_dep.path("vendor"));
|
||||
}
|
||||
},
|
||||
|
||||
.inproc => lib.addCSourceFiles(.{
|
||||
.inproc => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/backends/sentry_backend_inproc.c",
|
||||
@@ -190,7 +190,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.flags = flags.items,
|
||||
}),
|
||||
|
||||
.none => lib.addCSourceFiles(.{
|
||||
.none => lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = &.{
|
||||
"src/backends/sentry_backend_none.c",
|
||||
|
||||
@@ -10,26 +10,21 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
// We link libcpp even with no_libcxx because simdutf requires
|
||||
// libc++ headers at build time. But it doesn't require libc++ at
|
||||
// runtime. For Ghostty itself, we have CI tests to verify this.
|
||||
//
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime
|
||||
// headers. The MSVC SDK include directories (added via linkLibC)
|
||||
// contain both C and C++ headers, so linkLibCpp is not needed.
|
||||
.link_libcpp = target.result.abi != .msvc,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.addIncludePath(b.path("vendor"));
|
||||
lib.linkLibC();
|
||||
libcpp: {
|
||||
if (target.result.abi == .msvc) {
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime headers.
|
||||
// The MSVC SDK include directories (added via linkLibC) contain
|
||||
// both C and C++ headers, so linkLibCpp is not needed.
|
||||
break :libcpp;
|
||||
}
|
||||
|
||||
// We link libcpp even with no_libcxx because simdutf requires
|
||||
// libc++ headers at build time. But it doesn't require libc++
|
||||
// at runtime. For Ghostty itself, we have CI tests to verify this.
|
||||
lib.linkLibCpp();
|
||||
}
|
||||
lib.root_module.addIncludePath(b.path("vendor"));
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
@@ -70,11 +65,15 @@ pub fn build(b: *std.Build) !void {
|
||||
try flags.append(b.allocator, "-std=c++17");
|
||||
}
|
||||
|
||||
if (target.result.os.tag == .freebsd or target.result.abi == .musl) {
|
||||
if (target.result.os.tag == .freebsd or
|
||||
target.result.abi == .musl or
|
||||
target.result.abi == .android or
|
||||
target.result.abi == .androideabi)
|
||||
{
|
||||
try flags.append(b.allocator, "-fPIC");
|
||||
}
|
||||
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.flags = flags.items,
|
||||
.files = &.{
|
||||
"vendor/simdutf.cpp",
|
||||
|
||||
@@ -34,12 +34,12 @@ pub fn build(b: *std.Build) !void {
|
||||
if (b.systemIntegrationOption("spirv-cross", .{})) {
|
||||
module.linkSystemLibrary("spirv-cross-c-shared", dynamic_link_opts);
|
||||
if (test_exe) |exe| {
|
||||
exe.linkSystemLibrary2("spirv-cross-c-shared", dynamic_link_opts);
|
||||
exe.root_module.linkSystemLibrary("spirv-cross-c-shared", dynamic_link_opts);
|
||||
}
|
||||
} else {
|
||||
const lib = try buildSpirvCross(b, module, target, optimize);
|
||||
b.installArtifact(lib);
|
||||
if (test_exe) |exe| exe.linkLibrary(lib);
|
||||
if (test_exe) |exe| exe.root_module.linkLibrary(lib);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,18 +54,16 @@ fn buildSpirvCross(
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime
|
||||
// headers. The MSVC SDK include directories (added via linkLibC)
|
||||
// contain both C and C++ headers, so linkLibCpp is not needed.
|
||||
.link_libcpp = target.result.abi != .msvc,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
||||
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
||||
// include paths, which conflict with MSVC's own C++ runtime headers.
|
||||
// The MSVC SDK include directories (added via linkLibC) contain
|
||||
// both C and C++ headers, so linkLibCpp is not needed.
|
||||
if (target.result.abi != .msvc) {
|
||||
lib.linkLibCpp();
|
||||
}
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
@@ -86,9 +84,9 @@ fn buildSpirvCross(
|
||||
}
|
||||
|
||||
if (b.lazyDependency("spirv_cross", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addIncludePath(upstream.path(""));
|
||||
module.addIncludePath(upstream.path(""));
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.flags = flags.items,
|
||||
.files = &.{
|
||||
|
||||
@@ -1,5 +1,38 @@
|
||||
const std = @import("std");
|
||||
|
||||
// All the C macros defined so that the header matches the build.
|
||||
const defines = [_][]const u8{
|
||||
"WUFFS_CONFIG__MODULES",
|
||||
"WUFFS_CONFIG__MODULE__AUX__BASE",
|
||||
"WUFFS_CONFIG__MODULE__AUX__IMAGE",
|
||||
"WUFFS_CONFIG__MODULE__BASE",
|
||||
"WUFFS_CONFIG__MODULE__ADLER32",
|
||||
"WUFFS_CONFIG__MODULE__CRC32",
|
||||
"WUFFS_CONFIG__MODULE__DEFLATE",
|
||||
"WUFFS_CONFIG__MODULE__JPEG",
|
||||
"WUFFS_CONFIG__MODULE__PNG",
|
||||
"WUFFS_CONFIG__MODULE__ZLIB",
|
||||
};
|
||||
|
||||
// Generated C code, includes the macros above. Designed to mimic old c.zig.
|
||||
// TODO: is this still needed, or are the -D flags enough?
|
||||
const wuffs_c_source = wuffs_c_source: {
|
||||
const include: []const u8 = "#include <wuffs-v0.4.c>";
|
||||
const len = len: {
|
||||
var len: usize = 0;
|
||||
for (defines) |d| len += std.fmt.count("#define {s}\n", .{d});
|
||||
len += std.fmt.count("{s}\n", .{include});
|
||||
break :len len;
|
||||
};
|
||||
|
||||
var buf: [len:0]u8 = undefined;
|
||||
var writer: std.Io.Writer = .fixed(&buf);
|
||||
for (defines) |d| writer.print("#define {s}\n", .{d}) catch unreachable;
|
||||
writer.print("{s}\n", .{include}) catch unreachable;
|
||||
buf[len] = 0;
|
||||
break :wuffs_c_source buf;
|
||||
};
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
@@ -15,25 +48,41 @@ pub fn build(b: *std.Build) !void {
|
||||
.name = "test",
|
||||
.root_module = module,
|
||||
});
|
||||
unit_tests.linkLibC();
|
||||
|
||||
var flags: std.ArrayList([]const u8) = .empty;
|
||||
defer flags.deinit(b.allocator);
|
||||
try flags.append(b.allocator, "-DWUFFS_IMPLEMENTATION");
|
||||
if (target.result.abi == .msvc) {
|
||||
try flags.append(b.allocator, "-fno-sanitize=undefined");
|
||||
try flags.append(b.allocator, "-fno-sanitize-trap=undefined");
|
||||
}
|
||||
inline for (@import("src/c.zig").defines) |key| {
|
||||
try flags.append(b.allocator, "-D" ++ key);
|
||||
}
|
||||
|
||||
if (b.lazyDependency("wuffs", .{})) |wuffs_dep| {
|
||||
module.addIncludePath(wuffs_dep.path("release/c"));
|
||||
module.addCSourceFile(.{
|
||||
.file = wuffs_dep.path("release/c/wuffs-v0.4.c"),
|
||||
.flags = flags.items,
|
||||
translate: {
|
||||
const translate_c = b.lazyImport(@This(), "translate_c") orelse break :translate;
|
||||
const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse break :translate;
|
||||
const wuffs_c: translate_c.Translator = .init(translate_c_dep, .{
|
||||
.c_source_file = b.addWriteFiles().add("wuffs_c.h", &wuffs_c_source),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.libc_file = if (target.result.os.tag.isDarwin()) libc_file: {
|
||||
switch (try @import("apple_sdk").pathsForTarget(b, target.result)) {
|
||||
inline else => |paths| break :libc_file paths.libc,
|
||||
}
|
||||
} else null,
|
||||
});
|
||||
|
||||
var flags: std.ArrayList([]const u8) = .empty;
|
||||
defer flags.deinit(b.allocator);
|
||||
try flags.append(b.allocator, "-DWUFFS_IMPLEMENTATION");
|
||||
if (target.result.abi == .msvc) {
|
||||
try flags.append(b.allocator, "-fno-sanitize=undefined");
|
||||
try flags.append(b.allocator, "-fno-sanitize-trap=undefined");
|
||||
}
|
||||
inline for (defines) |key| {
|
||||
try flags.append(b.allocator, "-D" ++ key);
|
||||
}
|
||||
|
||||
if (b.lazyDependency("wuffs", .{})) |wuffs_dep| {
|
||||
wuffs_c.addIncludePath(wuffs_dep.path("release/c"));
|
||||
wuffs_c.mod.addCSourceFile(.{
|
||||
.file = wuffs_dep.path("release/c/wuffs-v0.4.c"),
|
||||
.flags = flags.items,
|
||||
});
|
||||
}
|
||||
|
||||
module.addImport("wuffs_c", wuffs_c.mod);
|
||||
}
|
||||
|
||||
if (b.lazyDependency("pixels", .{})) |pixels_dep| {
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
.version = "0.0.0",
|
||||
.fingerprint = 0x67c0c059de921c4f,
|
||||
.dependencies = .{
|
||||
.translate_c = .{
|
||||
.lazy = true,
|
||||
.url = "https://codeberg.org/vancluever/translate-c/archive/a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
.hash = "translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
},
|
||||
|
||||
// google/wuffs
|
||||
.wuffs = .{
|
||||
.url = "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
pub const c = @cImport({
|
||||
for (defines) |d| @cDefine(d, "1");
|
||||
@cInclude("wuffs-v0.4.c");
|
||||
});
|
||||
|
||||
/// All the C macros defined so that the header matches the build.
|
||||
pub const defines: []const []const u8 = &[_][]const u8{
|
||||
"WUFFS_CONFIG__MODULES",
|
||||
"WUFFS_CONFIG__MODULE__AUX__BASE",
|
||||
"WUFFS_CONFIG__MODULE__AUX__IMAGE",
|
||||
"WUFFS_CONFIG__MODULE__BASE",
|
||||
"WUFFS_CONFIG__MODULE__ADLER32",
|
||||
"WUFFS_CONFIG__MODULE__CRC32",
|
||||
"WUFFS_CONFIG__MODULE__DEFLATE",
|
||||
"WUFFS_CONFIG__MODULE__JPEG",
|
||||
"WUFFS_CONFIG__MODULE__PNG",
|
||||
"WUFFS_CONFIG__MODULE__ZLIB",
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("wuffs_c");
|
||||
|
||||
pub const Error = std.mem.Allocator.Error || error{ WuffsError, Overflow };
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("wuffs_c");
|
||||
const Error = @import("error.zig").Error;
|
||||
const check = @import("error.zig").check;
|
||||
const ImageData = @import("main.zig").ImageData;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
|
||||
pub const png = @import("png.zig");
|
||||
@@ -16,5 +17,19 @@ pub const ImageData = struct {
|
||||
};
|
||||
|
||||
test {
|
||||
std.testing.refAllDeclsRecursive(@This());
|
||||
refAllDeclsRecursive(@This());
|
||||
}
|
||||
|
||||
/// Copied from 0.15.2 stdlib (MIT license).
|
||||
fn refAllDeclsRecursive(comptime T: type) void {
|
||||
if (!builtin.is_test) return;
|
||||
inline for (comptime std.meta.declarations(T)) |decl| {
|
||||
if (@TypeOf(@field(T, decl.name)) == type) {
|
||||
switch (@typeInfo(@field(T, decl.name))) {
|
||||
.@"struct", .@"enum", .@"union", .@"opaque" => refAllDeclsRecursive(@field(T, decl.name)),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
_ = &@field(T, decl.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("wuffs_c");
|
||||
const Error = @import("error.zig").Error;
|
||||
const check = @import("error.zig").check;
|
||||
const ImageData = @import("main.zig").ImageData;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("wuffs_c");
|
||||
const Error = @import("error.zig").Error;
|
||||
|
||||
const log = std.log.scoped(.wuffs_swizzler);
|
||||
|
||||
@@ -9,17 +9,17 @@ pub fn build(b: *std.Build) !void {
|
||||
.root_module = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.linkage = .static,
|
||||
});
|
||||
lib.linkLibC();
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
if (b.lazyDependency("zlib", .{})) |upstream| {
|
||||
lib.addIncludePath(upstream.path(""));
|
||||
lib.root_module.addIncludePath(upstream.path(""));
|
||||
lib.installHeadersDirectory(
|
||||
upstream.path(""),
|
||||
"",
|
||||
@@ -48,7 +48,7 @@ pub fn build(b: *std.Build) !void {
|
||||
"-D_CRT_NONSTDC_NO_DEPRECATE",
|
||||
});
|
||||
}
|
||||
lib.addCSourceFiles(.{
|
||||
lib.root_module.addCSourceFiles(.{
|
||||
.root = upstream.path(""),
|
||||
.files = srcs,
|
||||
.flags = flags.items,
|
||||
|
||||
@@ -15,6 +15,7 @@ const Config = configpkg.Config;
|
||||
const BlockingQueue = @import("datastruct/main.zig").BlockingQueue;
|
||||
const renderer = @import("renderer.zig");
|
||||
const font = @import("font/main.zig");
|
||||
const global = @import("global.zig");
|
||||
|
||||
const log = std.log.scoped(.app);
|
||||
|
||||
@@ -56,7 +57,7 @@ font_grid_set: font.SharedGridSet,
|
||||
// Used to rate limit desktop notifications. Some platforms (notably macOS) will
|
||||
// run out of resources if desktop notifications are sent too fast and the OS
|
||||
// will kill Ghostty.
|
||||
last_notification_time: ?std.time.Instant = null,
|
||||
last_notification_time: ?std.Io.Timestamp = null,
|
||||
last_notification_digest: u64 = 0,
|
||||
|
||||
/// The conditional state of the configuration. See the equivalent field
|
||||
@@ -95,7 +96,7 @@ pub fn init(
|
||||
|
||||
self.* = .{
|
||||
.alloc = alloc,
|
||||
.surfaces = .{},
|
||||
.surfaces = .empty,
|
||||
.mailbox = .{},
|
||||
.font_grid_set = font_grid_set,
|
||||
.config_conditional_state = .{},
|
||||
@@ -236,7 +237,7 @@ pub fn needsConfirmQuit(self: *const App) bool {
|
||||
|
||||
/// Drain the mailbox.
|
||||
fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
|
||||
while (self.mailbox.pop()) |message| {
|
||||
while (self.mailbox.pop(global.io())) |message| {
|
||||
if (comptime std.log.logEnabled(.debug, .app)) {
|
||||
switch (message) {
|
||||
// these tend to be way too verbose for normal debugging
|
||||
@@ -566,7 +567,7 @@ pub const Mailbox = struct {
|
||||
|
||||
/// Send a message to the surface.
|
||||
pub fn push(self: Mailbox, msg: Message, timeout: Queue.Timeout) Queue.Size {
|
||||
const result = self.mailbox.push(msg, timeout);
|
||||
const result = self.mailbox.push(global.io(), msg, timeout);
|
||||
|
||||
// Wake up our app loop
|
||||
self.rt_app.wakeup();
|
||||
|
||||
277
src/Command.zig
277
src/Command.zig
@@ -14,12 +14,15 @@
|
||||
//! * posix_spawn is used for Mac, but doesn't support the necessary
|
||||
//! features for tty setup.
|
||||
//!
|
||||
//!
|
||||
//! TODO: This may have changed a lot now with the new I/O implementations in
|
||||
//! >= 0.16.0, so this might warrant a recheck.
|
||||
const Command = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const configpkg = @import("config.zig");
|
||||
const global_state = &@import("global.zig").state;
|
||||
const global = @import("global.zig");
|
||||
const internal_os = @import("os/main.zig");
|
||||
const windows = internal_os.windows;
|
||||
const TempDir = internal_os.TempDir;
|
||||
@@ -29,8 +32,8 @@ const posix = std.posix;
|
||||
const debug = std.debug;
|
||||
const testing = std.testing;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const File = std.fs.File;
|
||||
const EnvMap = std.process.EnvMap;
|
||||
const File = std.Io.File;
|
||||
const EnvMap = std.process.Environ.Map;
|
||||
const apprt = @import("apprt.zig");
|
||||
|
||||
/// Function prototype for a function executed /in the child process/ after the
|
||||
@@ -65,7 +68,7 @@ env: ?*const EnvMap = null,
|
||||
|
||||
/// Working directory to change to in the child process. If not set, the
|
||||
/// working directory of the calling process is preserved.
|
||||
cwd: ?[]const u8 = null,
|
||||
cwd: ?[:0]const u8 = null,
|
||||
|
||||
/// The file handle to set for stdin/out/err. If this isn't set, we do
|
||||
/// nothing explicitly so it is up to the behavior of the operating system.
|
||||
@@ -98,7 +101,7 @@ rt_post_fork_info: RtPostForkInfo,
|
||||
|
||||
/// If set, then the process will be created attached to this pseudo console.
|
||||
/// `stdin`, `stdout`, and `stderr` will be ignored if set.
|
||||
pseudo_console: if (builtin.os.tag == .windows) ?windows.exp.HPCON else void =
|
||||
pseudo_console: if (builtin.os.tag == .windows) ?windows.HPCON else void =
|
||||
if (builtin.os.tag == .windows) null else {},
|
||||
|
||||
/// User data that is sent to the callback. Set with setData and getData
|
||||
@@ -106,7 +109,7 @@ pseudo_console: if (builtin.os.tag == .windows) ?windows.exp.HPCON else void =
|
||||
data: ?*anyopaque = null,
|
||||
|
||||
/// Process ID is set after start is called.
|
||||
pid: ?posix.pid_t = null,
|
||||
pid: ?posix.system.pid_t = null,
|
||||
|
||||
/// The various methods a process may exit.
|
||||
pub const Exit = if (builtin.os.tag == .windows) union(enum) {
|
||||
@@ -128,9 +131,9 @@ pub const Exit = if (builtin.os.tag == .windows) union(enum) {
|
||||
return if (posix.W.IFEXITED(status))
|
||||
Exit{ .Exited = posix.W.EXITSTATUS(status) }
|
||||
else if (posix.W.IFSIGNALED(status))
|
||||
Exit{ .Signal = posix.W.TERMSIG(status) }
|
||||
Exit{ .Signal = @intFromEnum(posix.W.TERMSIG(status)) }
|
||||
else if (posix.W.IFSTOPPED(status))
|
||||
Exit{ .Stopped = posix.W.STOPSIG(status) }
|
||||
Exit{ .Stopped = @intFromEnum(posix.W.STOPSIG(status)) }
|
||||
else
|
||||
Exit{ .Unknown = status };
|
||||
}
|
||||
@@ -186,7 +189,7 @@ fn startPosix(self: *Command, arena: Allocator) !void {
|
||||
@compileError("missing env vars");
|
||||
|
||||
// Fork.
|
||||
const pid = try posix.fork();
|
||||
const pid = posix.system.fork();
|
||||
|
||||
if (pid != 0) {
|
||||
// Parent, return immediately.
|
||||
@@ -205,37 +208,68 @@ fn startPosix(self: *Command, arena: Allocator) !void {
|
||||
if (self.stderr) |f| setupFd(f.handle, posix.STDERR_FILENO) catch
|
||||
return error.ExecFailedInChild;
|
||||
|
||||
// Setup our working directory
|
||||
if (self.cwd) |cwd| posix.chdir(cwd) catch {
|
||||
// This can fail if we don't have permission to go to
|
||||
// this directory or if due to race conditions it doesn't
|
||||
// exist or any various other reasons. We don't want to
|
||||
// crash the entire process if this fails so we ignore it.
|
||||
// We don't log because that'll show up in the output.
|
||||
};
|
||||
// Setup our working directory.
|
||||
//
|
||||
// NOTE: this can fail if we don't have permission to go to this directory
|
||||
// or if due to race conditions it doesn't exist or any various other
|
||||
// reasons. We don't want to crash the entire process if this fails so we
|
||||
// ignore it. We don't log because that'll show up in the output.
|
||||
if (self.cwd) |cwd| _ = posix.system.chdir(cwd);
|
||||
|
||||
// Restore any rlimits that were set by Ghostty. This might fail but
|
||||
// any failures are ignored (its best effort).
|
||||
global_state.rlimits.restore();
|
||||
global.rlimits().restore();
|
||||
|
||||
// If there are pre exec callbacks, call them now.
|
||||
if (self.os_pre_exec) |f| if (f(self)) |exitcode| posix.exit(exitcode);
|
||||
if (self.rt_pre_exec) |f| if (f(self)) |exitcode| posix.exit(exitcode);
|
||||
if (self.os_pre_exec) |f| if (f(self)) |exitcode| posix.system.exit(exitcode);
|
||||
if (self.rt_pre_exec) |f| if (f(self)) |exitcode| posix.system.exit(exitcode);
|
||||
|
||||
// Finally, replace our process.
|
||||
// Note: we must use the "p"-variant of exec here because we
|
||||
// do not guarantee our command is looked up already in the path.
|
||||
const err = posix.execvpeZ(self.path, argsZ, envp);
|
||||
const err: posix.E = execve: {
|
||||
// This functionality has been taken from Zig stdlib, a simplified
|
||||
// version of the exec bits with PATH search so that we can just
|
||||
// offload to execve below.
|
||||
const file_slice = std.mem.sliceTo(self.path, 0);
|
||||
if (std.mem.findScalar(u8, file_slice, '/') != null) {
|
||||
break :execve posix.errno(posix.system.execve(self.path, argsZ, envp));
|
||||
}
|
||||
|
||||
var path_expanded_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
const PATH = global.environ().getPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
|
||||
var it = std.mem.tokenizeScalar(u8, PATH, ':');
|
||||
var err: posix.system.E = undefined;
|
||||
var seen_eacces = false;
|
||||
|
||||
while (it.next()) |search_path| {
|
||||
const path_len = search_path.len + file_slice.len + 1;
|
||||
if (path_expanded_buf.len < path_len + 1) return error.NameTooLong;
|
||||
@memcpy(path_expanded_buf[0..search_path.len], search_path);
|
||||
path_expanded_buf[search_path.len] = '/';
|
||||
@memcpy(path_expanded_buf[search_path.len + 1 ..][0..file_slice.len], file_slice);
|
||||
path_expanded_buf[path_len] = 0;
|
||||
const full_path = path_expanded_buf[0..path_len :0].ptr;
|
||||
// Replace here, switch on error (any error means that replace
|
||||
// failed, but we might need to retry).
|
||||
err = posix.errno(posix.system.execve(full_path, argsZ, envp));
|
||||
switch (err) {
|
||||
.ACCES => seen_eacces = true,
|
||||
.NOENT, .NOTDIR => {},
|
||||
else => break :execve err,
|
||||
}
|
||||
}
|
||||
|
||||
if (seen_eacces) break :execve .ACCES;
|
||||
break :execve err;
|
||||
};
|
||||
|
||||
// If we are executing this code, the exec failed. We're in the
|
||||
// child process so there isn't much we can do. We try to output
|
||||
// something reasonable. Its important to note we MUST NOT return
|
||||
// any other error condition from here on out.
|
||||
var stderr_buf: [1024]u8 = undefined;
|
||||
var stderr_writer = std.fs.File.stderr().writer(&stderr_buf);
|
||||
var stderr_writer = std.Io.File.stderr().writer(global.io(), &stderr_buf);
|
||||
const stderr = &stderr_writer.interface;
|
||||
switch (err) {
|
||||
error.FileNotFound => stderr.print(
|
||||
posix.system.E.NOENT => stderr.print(
|
||||
\\Requested executable not found. Please verify the command is on
|
||||
\\the PATH and try again.
|
||||
\\
|
||||
@@ -243,11 +277,11 @@ fn startPosix(self: *Command, arena: Allocator) !void {
|
||||
.{},
|
||||
) catch {},
|
||||
|
||||
else => stderr.print(
|
||||
\\exec syscall failed with unexpected error: {}
|
||||
else => |e| stderr.print(
|
||||
\\exec syscall failed with unexpected error: E{s}
|
||||
\\
|
||||
,
|
||||
.{err},
|
||||
.{@tagName(e)},
|
||||
) catch {},
|
||||
}
|
||||
stderr.flush() catch {};
|
||||
@@ -275,15 +309,37 @@ fn startWindows(self: *Command, arena: Allocator) !void {
|
||||
const env_w = if (self.env) |env_map| try createWindowsEnvBlock(arena, env_map) else null;
|
||||
|
||||
const any_null_fd = self.stdin == null or self.stdout == null or self.stderr == null;
|
||||
const null_fd = if (any_null_fd) try windows.OpenFile(
|
||||
&[_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' },
|
||||
.{
|
||||
.access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE,
|
||||
.share_access = windows.FILE_SHARE_READ,
|
||||
.creation = windows.OPEN_EXISTING,
|
||||
},
|
||||
) else null;
|
||||
defer if (null_fd) |fd| posix.close(fd);
|
||||
const null_fd = if (any_null_fd) null_fd: {
|
||||
// path = "\Device\Null"
|
||||
const path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' };
|
||||
var path_unicode_string: windows.UNICODE_STRING = .init(&path);
|
||||
var attrs: windows.OBJECT_ATTRIBUTES = .{ .ObjectName = &path_unicode_string };
|
||||
|
||||
var fd: windows.HANDLE = undefined;
|
||||
var io_status: windows.IO_STATUS_BLOCK = undefined; // unused
|
||||
const result = windows.exp.ntdll.NtCreateFile(
|
||||
&fd,
|
||||
.{ .GENERIC = .{ .READ = true }, .STANDARD = .{ .SYNCHRONIZE = true } },
|
||||
&attrs,
|
||||
&io_status,
|
||||
null,
|
||||
windows.FILE_ATTRIBUTE_NORMAL,
|
||||
windows.FILE_SHARE_READ,
|
||||
windows.OPEN_EXISTING,
|
||||
windows.FILE_NON_DIRECTORY_FILE,
|
||||
null,
|
||||
0,
|
||||
);
|
||||
|
||||
if (result != .SUCCESS) {
|
||||
return windows.unexpectedStatus(result);
|
||||
}
|
||||
|
||||
break :null_fd fd;
|
||||
} else null;
|
||||
defer {
|
||||
if (null_fd) |fd| _ = windows.exp.kernel32.CloseHandle(fd);
|
||||
}
|
||||
|
||||
// TODO: In the case of having FDs instead of pty, need to set up
|
||||
// attributes such that the child process only inherits these handles,
|
||||
@@ -304,17 +360,17 @@ fn startWindows(self: *Command, arena: Allocator) !void {
|
||||
1,
|
||||
0,
|
||||
&attribute_list_size,
|
||||
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||
) == windows.FALSE) return windows.unexpectedError(windows.GetLastError());
|
||||
|
||||
if (windows.exp.kernel32.UpdateProcThreadAttribute(
|
||||
attribute_list_buf.ptr,
|
||||
0,
|
||||
windows.exp.PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
windows.PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
pseudo_console,
|
||||
@sizeOf(windows.exp.HPCON),
|
||||
@sizeOf(windows.HPCON),
|
||||
null,
|
||||
null,
|
||||
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||
) == windows.FALSE) return windows.unexpectedError(windows.GetLastError());
|
||||
|
||||
break :b .{ attribute_list_buf.ptr, null, null, null };
|
||||
} else b: {
|
||||
@@ -324,9 +380,9 @@ fn startWindows(self: *Command, arena: Allocator) !void {
|
||||
break :b .{ null, stdin, stdout, stderr };
|
||||
};
|
||||
|
||||
var startup_info_ex = windows.exp.STARTUPINFOEX{
|
||||
var startup_info_ex = windows.STARTUPINFOEX{
|
||||
.StartupInfo = .{
|
||||
.cb = if (attribute_list != null) @sizeOf(windows.exp.STARTUPINFOEX) else @sizeOf(windows.STARTUPINFOW),
|
||||
.cb = if (attribute_list != null) @sizeOf(windows.STARTUPINFOEX) else @sizeOf(windows.STARTUPINFOW),
|
||||
.hStdError = stderr,
|
||||
.hStdOutput = stdout,
|
||||
.hStdInput = stdin,
|
||||
@@ -348,8 +404,8 @@ fn startWindows(self: *Command, arena: Allocator) !void {
|
||||
.lpAttributeList = attribute_list,
|
||||
};
|
||||
|
||||
var flags: windows.DWORD = windows.exp.CREATE_UNICODE_ENVIRONMENT;
|
||||
if (attribute_list != null) flags |= windows.exp.EXTENDED_STARTUPINFO_PRESENT;
|
||||
var flags: windows.DWORD = windows.CREATE_UNICODE_ENVIRONMENT;
|
||||
if (attribute_list != null) flags |= windows.EXTENDED_STARTUPINFO_PRESENT;
|
||||
|
||||
var process_information: windows.PROCESS_INFORMATION = undefined;
|
||||
if (windows.exp.kernel32.CreateProcessW(
|
||||
@@ -363,21 +419,18 @@ fn startWindows(self: *Command, arena: Allocator) !void {
|
||||
if (cwd_w) |w| w.ptr else null,
|
||||
@ptrCast(&startup_info_ex.StartupInfo),
|
||||
&process_information,
|
||||
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||
) == windows.FALSE) return windows.unexpectedError(windows.GetLastError());
|
||||
|
||||
self.pid = process_information.hProcess;
|
||||
}
|
||||
|
||||
fn setupFd(src: File.Handle, target: i32) !void {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
// We use dup3 so that we can clear CLO_ON_EXEC. We do NOT want this
|
||||
// file descriptor to be closed on exec since we're exactly exec-ing after
|
||||
// this.
|
||||
const PosixCall = struct {
|
||||
fn f(func: anytype, args: anytype) !usize {
|
||||
while (true) {
|
||||
const rc = linux.dup3(src, target, 0);
|
||||
const rc = @call(.auto, func, args);
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => break,
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.INTR => continue,
|
||||
.AGAIN, .ACCES => return error.Locked,
|
||||
.BADF => unreachable,
|
||||
@@ -391,16 +444,28 @@ fn setupFd(src: File.Handle, target: i32) !void {
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
// We use dup3 so that we can clear CLO_ON_EXEC. We do NOT want this
|
||||
// file descriptor to be closed on exec since we're exactly exec-ing after
|
||||
// this.
|
||||
_ = try PosixCall.f(linux.dup3, .{ src, target, 0 });
|
||||
},
|
||||
.freebsd, .ios, .macos => {
|
||||
// Mac doesn't support dup3 so we use dup2. We purposely clear
|
||||
// CLO_ON_EXEC for this fd.
|
||||
const flags = try posix.fcntl(src, posix.F.GETFD, 0);
|
||||
const flags = try PosixCall.f(posix.system.fcntl, .{ src, posix.F.GETFD });
|
||||
if (flags & posix.FD_CLOEXEC != 0) {
|
||||
_ = try posix.fcntl(src, posix.F.SETFD, flags & ~@as(u32, posix.FD_CLOEXEC));
|
||||
_ = try PosixCall.f(
|
||||
posix.system.fcntl,
|
||||
.{ src, posix.F.SETFD, flags & ~@as(u32, posix.FD_CLOEXEC) },
|
||||
);
|
||||
}
|
||||
|
||||
try posix.dup2(src, target);
|
||||
_ = try PosixCall.f(posix.system.dup2, .{ src, target });
|
||||
},
|
||||
else => @compileError("unsupported platform"),
|
||||
}
|
||||
@@ -411,21 +476,29 @@ pub fn wait(self: Command, block: bool) !Exit {
|
||||
if (comptime builtin.os.tag == .windows) {
|
||||
// Block until the process exits. This returns immediately if the
|
||||
// process already exited.
|
||||
const result = windows.kernel32.WaitForSingleObject(self.pid.?, windows.INFINITE);
|
||||
//
|
||||
// NOTE: We can use the pid directly as posix.system.pid_t is still an
|
||||
// alias for a handle under Windows. We might want to keep an eye on if
|
||||
// this changes, though.
|
||||
const result = windows.exp.kernel32.WaitForSingleObject(self.pid.?, windows.INFINITE);
|
||||
if (result == windows.WAIT_FAILED) {
|
||||
return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||
return windows.unexpectedError(windows.GetLastError());
|
||||
}
|
||||
|
||||
var exit_code: windows.DWORD = undefined;
|
||||
const has_code = windows.kernel32.GetExitCodeProcess(self.pid.?, &exit_code) != 0;
|
||||
const has_code = windows.exp.kernel32.GetExitCodeProcess(self.pid.?, &exit_code) != windows.FALSE;
|
||||
if (!has_code) {
|
||||
return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||
return windows.unexpectedError(windows.GetLastError());
|
||||
}
|
||||
|
||||
return .{ .Exited = exit_code };
|
||||
}
|
||||
|
||||
const res = if (block) posix.waitpid(self.pid.?, 0) else res: {
|
||||
const status = if (block) wait_block: {
|
||||
var status: c_int = undefined;
|
||||
_ = posix.system.waitpid(self.pid.?, &status, 0);
|
||||
break :wait_block status;
|
||||
} else wait_nohang: {
|
||||
// We specify NOHANG because its not our fault if the process we launch
|
||||
// for the tty doesn't properly waitpid its children. We don't want
|
||||
// to hang the terminal over it.
|
||||
@@ -434,12 +507,13 @@ pub fn wait(self: Command, block: bool) !Exit {
|
||||
// wait call has not been performed, so we need to keep trying until we get
|
||||
// a non-zero pid back, otherwise we end up with zombie processes.
|
||||
while (true) {
|
||||
const res = posix.waitpid(self.pid.?, std.c.W.NOHANG);
|
||||
if (res.pid != 0) break :res res;
|
||||
var status: c_int = undefined;
|
||||
const pid = posix.system.waitpid(self.pid.?, &status, posix.system.W.NOHANG);
|
||||
if (pid != 0) break :wait_nohang status;
|
||||
}
|
||||
};
|
||||
|
||||
return .init(res.status);
|
||||
return .init(@bitCast(status));
|
||||
}
|
||||
|
||||
/// Sets command->data to data.
|
||||
@@ -587,7 +661,7 @@ test "Command: os pre exec 1" {
|
||||
fn do(_: *Command) ?u8 {
|
||||
// This runs in the child, so we can exit and it won't
|
||||
// kill the test runner.
|
||||
posix.exit(42);
|
||||
posix.system.exit(42);
|
||||
}
|
||||
}).do,
|
||||
.rt_pre_exec = null,
|
||||
@@ -638,7 +712,7 @@ test "Command: rt pre exec 1" {
|
||||
fn do(_: *Command) ?u8 {
|
||||
// This runs in the child, so we can exit and it won't
|
||||
// kill the test runner.
|
||||
posix.exit(42);
|
||||
posix.system.exit(42);
|
||||
}
|
||||
}).do,
|
||||
.rt_post_fork = null,
|
||||
@@ -697,27 +771,31 @@ test "Command: rt post fork 1" {
|
||||
try testing.expectError(error.PostForkError, cmd.testingStart());
|
||||
}
|
||||
|
||||
fn createTestStdout(dir: std.fs.Dir) !File {
|
||||
const file = try dir.createFile("stdout.txt", .{ .read = true });
|
||||
fn createTestStdout(io: std.Io, dir: std.Io.Dir) !File {
|
||||
const file = try dir.createFile(io, "stdout.txt", .{ .read = true });
|
||||
if (builtin.os.tag == .windows) {
|
||||
try windows.SetHandleInformation(
|
||||
if (windows.exp.kernel32.SetHandleInformation(
|
||||
file.handle,
|
||||
windows.HANDLE_FLAG_INHERIT,
|
||||
windows.HANDLE_FLAG_INHERIT,
|
||||
);
|
||||
) == windows.FALSE) {
|
||||
return windows.unexpectedError(windows.GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
fn createTestStderr(dir: std.fs.Dir) !File {
|
||||
const file = try dir.createFile("stderr.txt", .{ .read = true });
|
||||
fn createTestStderr(io: std.Io, dir: std.Io.Dir) !File {
|
||||
const file = try dir.createFile(io, "stderr.txt", .{ .read = true });
|
||||
if (builtin.os.tag == .windows) {
|
||||
try windows.SetHandleInformation(
|
||||
if (windows.exp.kernel32.SetHandleInformation(
|
||||
file.handle,
|
||||
windows.HANDLE_FLAG_INHERIT,
|
||||
windows.HANDLE_FLAG_INHERIT,
|
||||
);
|
||||
) == windows.FALSE) {
|
||||
return windows.unexpectedError(windows.GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
@@ -726,8 +804,8 @@ fn createTestStderr(dir: std.fs.Dir) !File {
|
||||
test "Command: redirect stdout to file" {
|
||||
var td = try TempDir.init();
|
||||
defer td.deinit();
|
||||
var stdout = try createTestStdout(td.dir);
|
||||
defer stdout.close();
|
||||
var stdout = try createTestStdout(testing.io, td.dir);
|
||||
defer stdout.close(testing.io);
|
||||
|
||||
var cmd: Command = if (builtin.os.tag == .windows) .{
|
||||
.path = "C:\\Windows\\System32\\whoami.exe",
|
||||
@@ -756,8 +834,13 @@ test "Command: redirect stdout to file" {
|
||||
try testing.expectEqual(@as(u32, 0), @as(u32, exit.Exited));
|
||||
|
||||
// Read our stdout
|
||||
try stdout.seekTo(0);
|
||||
const contents = try stdout.readToEndAlloc(testing.allocator, 1024 * 128);
|
||||
const contents = contents: {
|
||||
const size = (try stdout.stat(testing.io)).size;
|
||||
const data = try testing.allocator.alloc(u8, size);
|
||||
errdefer testing.allocator.free(data);
|
||||
try testing.expectEqual(size, try stdout.readPositionalAll(testing.io, data, 0));
|
||||
break :contents data;
|
||||
};
|
||||
defer testing.allocator.free(contents);
|
||||
try testing.expect(contents.len > 0);
|
||||
}
|
||||
@@ -765,8 +848,8 @@ test "Command: redirect stdout to file" {
|
||||
test "Command: custom env vars" {
|
||||
var td = try TempDir.init();
|
||||
defer td.deinit();
|
||||
var stdout = try createTestStdout(td.dir);
|
||||
defer stdout.close();
|
||||
var stdout = try createTestStdout(testing.io, td.dir);
|
||||
defer stdout.close(testing.io);
|
||||
|
||||
var env = EnvMap.init(testing.allocator);
|
||||
defer env.deinit();
|
||||
@@ -801,8 +884,13 @@ test "Command: custom env vars" {
|
||||
try testing.expect(exit.Exited == 0);
|
||||
|
||||
// Read our stdout
|
||||
try stdout.seekTo(0);
|
||||
const contents = try stdout.readToEndAlloc(testing.allocator, 4096);
|
||||
const contents = contents: {
|
||||
const size = (try stdout.stat(testing.io)).size;
|
||||
const data = try testing.allocator.alloc(u8, size);
|
||||
errdefer testing.allocator.free(data);
|
||||
try testing.expectEqual(size, try stdout.readPositionalAll(testing.io, data, 0));
|
||||
break :contents data;
|
||||
};
|
||||
defer testing.allocator.free(contents);
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
@@ -815,8 +903,8 @@ test "Command: custom env vars" {
|
||||
test "Command: custom working directory" {
|
||||
var td = try TempDir.init();
|
||||
defer td.deinit();
|
||||
var stdout = try createTestStdout(td.dir);
|
||||
defer stdout.close();
|
||||
var stdout = try createTestStdout(testing.io, td.dir);
|
||||
defer stdout.close(testing.io);
|
||||
|
||||
var cmd: Command = if (builtin.os.tag == .windows) .{
|
||||
.path = "C:\\Windows\\System32\\cmd.exe",
|
||||
@@ -847,8 +935,13 @@ test "Command: custom working directory" {
|
||||
try testing.expect(exit.Exited == 0);
|
||||
|
||||
// Read our stdout
|
||||
try stdout.seekTo(0);
|
||||
const contents = try stdout.readToEndAlloc(testing.allocator, 4096);
|
||||
const contents = contents: {
|
||||
const size = (try stdout.stat(testing.io)).size;
|
||||
const data = try testing.allocator.alloc(u8, size);
|
||||
errdefer testing.allocator.free(data);
|
||||
try testing.expectEqual(size, try stdout.readPositionalAll(testing.io, data, 0));
|
||||
break :contents data;
|
||||
};
|
||||
defer testing.allocator.free(contents);
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
@@ -872,10 +965,10 @@ test "Command: posix fork handles execveZ failure" {
|
||||
}
|
||||
var td = try TempDir.init();
|
||||
defer td.deinit();
|
||||
var stdout = try createTestStdout(td.dir);
|
||||
defer stdout.close();
|
||||
var stderr = try createTestStderr(td.dir);
|
||||
defer stderr.close();
|
||||
var stdout = try createTestStdout(testing.io, td.dir);
|
||||
defer stdout.close(testing.io);
|
||||
var stderr = try createTestStderr(testing.io, td.dir);
|
||||
defer stderr.close(testing.io);
|
||||
|
||||
var cmd: Command = .{
|
||||
.path = "/not/a/binary",
|
||||
@@ -904,7 +997,7 @@ fn testingStart(self: *Command) !void {
|
||||
self.start(testing.allocator) catch |err| {
|
||||
if (err == error.ExecFailedInChild) {
|
||||
// I am a child process, I must not get confused and continue running the rest of the test suite.
|
||||
posix.exit(1);
|
||||
posix.system.exit(1);
|
||||
}
|
||||
return err;
|
||||
};
|
||||
|
||||
294
src/Surface.zig
294
src/Surface.zig
@@ -20,7 +20,7 @@ const builtin = @import("builtin");
|
||||
const assert = @import("quirks.zig").inlineAssert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
const global_state = &@import("global.zig").state;
|
||||
const global = @import("global.zig");
|
||||
const oni = @import("oniguruma");
|
||||
const crash = @import("crash/main.zig");
|
||||
const unicode = @import("unicode/main.zig");
|
||||
@@ -168,13 +168,13 @@ readonly: bool = false,
|
||||
/// precision timestamp. It does not necessarily need to correspond to the
|
||||
/// actual time, but we must be able to compare two subsequent timestamps to get
|
||||
/// the wall clock time that has elapsed between timestamps.
|
||||
command_timer: ?std.time.Instant = null,
|
||||
command_timer: ?std.Io.Timestamp = null,
|
||||
|
||||
/// Search state
|
||||
search: ?Search = null,
|
||||
|
||||
/// Used to rate limit BEL handling.
|
||||
last_bell_time: ?std.time.Instant = null,
|
||||
last_bell_time: ?std.Io.Timestamp = null,
|
||||
|
||||
/// The effect of an input event. This can be used by callers to take
|
||||
/// the appropriate action after an input event. For example, key
|
||||
@@ -559,8 +559,8 @@ pub fn init(
|
||||
errdefer renderer_impl.deinit();
|
||||
|
||||
// The mutex used to protect our renderer state.
|
||||
const mutex = try alloc.create(std.Thread.Mutex);
|
||||
mutex.* = .{};
|
||||
const mutex = try alloc.create(std.Io.Mutex);
|
||||
mutex.* = .init;
|
||||
errdefer alloc.destroy(mutex);
|
||||
|
||||
// Create the renderer thread
|
||||
@@ -581,7 +581,11 @@ pub fn init(
|
||||
self.* = .{
|
||||
.id = id: {
|
||||
while (true) {
|
||||
const candidate = std.crypto.random.int(u64);
|
||||
const candidate = candidate: {
|
||||
const rng_impl: std.Random.IoSource = .{ .io = global.io() };
|
||||
const rng = rng_impl.interface();
|
||||
break :candidate rng.int(u64);
|
||||
};
|
||||
if (candidate == 0) continue;
|
||||
break :id candidate;
|
||||
}
|
||||
@@ -631,13 +635,12 @@ pub fn init(
|
||||
var env = rt_surface.defaultTermioEnv() catch |err| env: {
|
||||
// If an error occurs, we don't want to block surface startup.
|
||||
log.warn("error getting env map for surface err={}", .{err});
|
||||
break :env internal_os.getEnvMap(alloc) catch
|
||||
std.process.EnvMap.init(alloc);
|
||||
break :env global.environMap() catch std.process.Environ.Map.init(alloc);
|
||||
};
|
||||
errdefer env.deinit();
|
||||
|
||||
// don't leak GHOSTTY_LOG to any subprocesses
|
||||
env.remove("GHOSTTY_LOG");
|
||||
_ = env.orderedRemove("GHOSTTY_LOG");
|
||||
|
||||
var buf: [18]u8 = undefined;
|
||||
try env.put(
|
||||
@@ -654,7 +657,7 @@ pub fn init(
|
||||
.shell_integration_features = config.@"shell-integration-features",
|
||||
.cursor_blink = config.@"cursor-style-blink",
|
||||
.working_directory = if (config.@"working-directory") |wd| wd.value() else null,
|
||||
.resources_dir = global_state.resources_dir.host(),
|
||||
.resources_dir = global.resourcesDir().host(),
|
||||
.term = config.term,
|
||||
.rt_pre_exec_info = .init(config),
|
||||
.rt_post_fork_info = .init(config),
|
||||
@@ -717,7 +720,7 @@ pub fn init(
|
||||
rendererpkg.Thread.threadMain,
|
||||
.{&self.renderer_thread},
|
||||
);
|
||||
self.renderer_thr.setName("renderer") catch {};
|
||||
self.renderer_thr.setName(global.io(), "renderer") catch {};
|
||||
|
||||
// Start our IO thread
|
||||
self.io_thr = try std.Thread.spawn(
|
||||
@@ -725,7 +728,7 @@ pub fn init(
|
||||
termio.Thread.threadMain,
|
||||
.{ &self.io_thread, &self.io },
|
||||
);
|
||||
self.io_thr.setName("io") catch {};
|
||||
self.io_thr.setName(global.io(), "io") catch {};
|
||||
|
||||
// Determine our initial window size if configured. We need to do this
|
||||
// quite late in the process because our height/width are in grid dimensions,
|
||||
@@ -900,14 +903,14 @@ pub fn activateInspector(self: *Surface) !void {
|
||||
|
||||
// Put the inspector onto the render state
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
assert(self.renderer_state.inspector == null);
|
||||
self.renderer_state.inspector = self.inspector;
|
||||
}
|
||||
|
||||
// Notify our components we have an inspector active
|
||||
_ = self.renderer_thread.mailbox.push(.{ .inspector = true }, .{ .forever = {} });
|
||||
_ = self.renderer_thread.mailbox.push(global.io(), .{ .inspector = true }, .{ .forever = {} });
|
||||
self.queueIo(.{ .inspector = true }, .unlocked);
|
||||
}
|
||||
|
||||
@@ -917,14 +920,14 @@ pub fn deactivateInspector(self: *Surface) void {
|
||||
|
||||
// Remove the inspector from the render state
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
assert(self.renderer_state.inspector != null);
|
||||
self.renderer_state.inspector = null;
|
||||
}
|
||||
|
||||
// Notify our components we have deactivated inspector
|
||||
_ = self.renderer_thread.mailbox.push(.{ .inspector = false }, .{ .forever = {} });
|
||||
_ = self.renderer_thread.mailbox.push(global.io(), .{ .inspector = false }, .{ .forever = {} });
|
||||
self.queueIo(.{ .inspector = false }, .unlocked);
|
||||
|
||||
// Deinit the inspector
|
||||
@@ -948,8 +951,8 @@ pub fn needsConfirmQuit(self: *Surface) bool {
|
||||
.always => true,
|
||||
.false => false,
|
||||
.true => true: {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
break :true !self.io.terminal.cursorIsAtPrompt();
|
||||
},
|
||||
};
|
||||
@@ -1096,9 +1099,9 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
|
||||
.password_input => |v| try self.passwordInput(v),
|
||||
|
||||
.ring_bell => bell: {
|
||||
const now = std.time.Instant.now() catch unreachable;
|
||||
const now: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
if (self.last_bell_time) |last| {
|
||||
if (now.since(last) < 100 * std.time.ns_per_ms) break :bell;
|
||||
if (last.durationTo(now).toMilliseconds() < 100) break :bell;
|
||||
}
|
||||
self.last_bell_time = now;
|
||||
_ = self.rt_app.performAction(
|
||||
@@ -1126,15 +1129,22 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
|
||||
},
|
||||
|
||||
.start_command => {
|
||||
self.command_timer = try .now();
|
||||
self.command_timer = .now(global.io(), .awake);
|
||||
},
|
||||
|
||||
.stop_command => |v| timer: {
|
||||
const end: std.time.Instant = try .now();
|
||||
const end: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
const start = self.command_timer orelse break :timer;
|
||||
self.command_timer = null;
|
||||
const duration_raw = start.durationTo(end).nanoseconds;
|
||||
assert(duration_raw >= 0 and duration_raw <= std.math.maxInt(u64));
|
||||
|
||||
const duration: Duration = .{ .duration = end.since(start) };
|
||||
const duration: Duration = .{
|
||||
.duration = @as(
|
||||
u64,
|
||||
@intCast(std.math.clamp(start.durationTo(end).nanoseconds, 0, std.math.maxInt(u64))),
|
||||
),
|
||||
};
|
||||
log.debug("command took {f}", .{duration});
|
||||
|
||||
_ = self.rt_app.performAction(
|
||||
@@ -1185,8 +1195,8 @@ fn selectionScrollTick(self: *Surface) !void {
|
||||
const pos_vp = self.posToViewport(pos.x, pos.y);
|
||||
|
||||
// We need our locked state for the remainder
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||
|
||||
const selection = self.mouse.selection_gesture.autoscrollTick(t, .{
|
||||
@@ -1276,8 +1286,8 @@ fn childExited(self: *Surface, info: apprt.surface.Message.ChildExited) void {
|
||||
|
||||
// If the native GUI can't be shown, display a text message in the
|
||||
// terminal.
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||
t.carriageReturn();
|
||||
t.linefeed() catch break :terminal;
|
||||
@@ -1316,8 +1326,8 @@ fn childExitedAbnormally(
|
||||
});
|
||||
const runtime_str = try std.fmt.allocPrint(alloc, "{d} ms", .{info.runtime_ms});
|
||||
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||
|
||||
// No matter what move the cursor back to the column 0.
|
||||
@@ -1383,8 +1393,8 @@ fn childExitedAbnormally(
|
||||
/// Called when the terminal detects there is a password input prompt.
|
||||
fn passwordInput(self: *Surface, v: bool) !void {
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// If our password input state is unchanged then we don't
|
||||
// waste time doing anything more.
|
||||
@@ -1436,6 +1446,7 @@ fn searchCallback_(
|
||||
for (matches) |*m| m.* = try m.clone(alloc);
|
||||
|
||||
_ = self.renderer_thread.mailbox.push(
|
||||
global.io(),
|
||||
.{ .search_viewport_matches = .{
|
||||
.arena = arena,
|
||||
.matches = matches,
|
||||
@@ -1454,6 +1465,7 @@ fn searchCallback_(
|
||||
const match = try sel.highlight.clone(alloc);
|
||||
|
||||
_ = self.renderer_thread.mailbox.push(
|
||||
global.io(),
|
||||
.{ .search_selected_match = .{
|
||||
.arena = arena,
|
||||
.match = match,
|
||||
@@ -1469,6 +1481,7 @@ fn searchCallback_(
|
||||
} else {
|
||||
// Reset our selected match
|
||||
_ = self.renderer_thread.mailbox.push(
|
||||
global.io(),
|
||||
.{ .search_selected_match = null },
|
||||
.forever,
|
||||
);
|
||||
@@ -1493,10 +1506,12 @@ fn searchCallback_(
|
||||
// When we quit, tell our renderer to reset any search state.
|
||||
.quit => {
|
||||
_ = self.renderer_thread.mailbox.push(
|
||||
global.io(),
|
||||
.{ .search_selected_match = null },
|
||||
.forever,
|
||||
);
|
||||
_ = self.renderer_thread.mailbox.push(
|
||||
global.io(),
|
||||
.{ .search_viewport_matches = .{
|
||||
.arena = .init(self.alloc),
|
||||
.matches = &.{},
|
||||
@@ -1539,8 +1554,8 @@ fn modsChanged(self: *Surface, mods: input.Mods) void {
|
||||
// highlight links. Additionally, mark the screen as dirty so
|
||||
// that the highlight state of all links is properly updated.
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
self.renderer_state.mouse.mods = self.mouseModsWithCapture(self.mouse.mods);
|
||||
|
||||
// We use the clear screen dirty flag to force a rebuild of all
|
||||
@@ -1786,7 +1801,7 @@ pub fn updateConfig(
|
||||
termio_config_ptr.* = try termio.Termio.DerivedConfig.init(self.alloc, config);
|
||||
errdefer termio_config_ptr.deinit();
|
||||
|
||||
_ = self.renderer_thread.mailbox.push(renderer_message, .{ .forever = {} });
|
||||
_ = self.renderer_thread.mailbox.push(global.io(), renderer_message, .{ .forever = {} });
|
||||
self.queueIo(.{
|
||||
.change_config = .{
|
||||
.alloc = self.alloc,
|
||||
@@ -1907,8 +1922,8 @@ pub fn dumpText(
|
||||
alloc: Allocator,
|
||||
sel: terminal.Selection,
|
||||
) !Text {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
return try self.dumpTextLocked(alloc, sel);
|
||||
}
|
||||
|
||||
@@ -2033,15 +2048,15 @@ pub fn dumpTextLocked(
|
||||
|
||||
/// Returns true if the terminal has a selection.
|
||||
pub fn hasSelection(self: *const Surface) bool {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
return self.io.terminal.screens.active.selection != null;
|
||||
}
|
||||
|
||||
/// Returns the selected text. This is allocated.
|
||||
pub fn selectionString(self: *Surface, alloc: Allocator) !?[:0]const u8 {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const sel = self.io.terminal.screens.active.selection orelse return null;
|
||||
return try self.io.terminal.screens.active.selectionString(alloc, .{
|
||||
.sel = sel,
|
||||
@@ -2056,8 +2071,8 @@ pub fn pwd(
|
||||
self: *const Surface,
|
||||
alloc: Allocator,
|
||||
) Allocator.Error!?[]const u8 {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const terminal_pwd = self.io.terminal.getPwd() orelse return null;
|
||||
return try alloc.dupe(u8, terminal_pwd);
|
||||
}
|
||||
@@ -2074,7 +2089,7 @@ fn resolvePathForOpening(
|
||||
|
||||
const resolved = try std.fs.path.resolve(self.alloc, &.{ terminal_pwd, path });
|
||||
|
||||
std.fs.accessAbsolute(resolved, .{}) catch {
|
||||
std.Io.Dir.accessAbsolute(global.io(), resolved, .{}) catch {
|
||||
self.alloc.free(resolved);
|
||||
return null;
|
||||
};
|
||||
@@ -2088,10 +2103,10 @@ fn resolvePathForOpening(
|
||||
/// Returns the x/y coordinate of where the IME (Input Method Editor)
|
||||
/// keyboard should be rendered.
|
||||
pub fn imePoint(self: *const Surface) apprt.IMEPos {
|
||||
self.renderer_state.mutex.lock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
const cursor = self.renderer_state.terminal.screens.active.cursor;
|
||||
const preedit_width: usize = if (self.renderer_state.preedit) |preedit| preedit.width() else 0;
|
||||
self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// TODO: need to handle when scrolling and the cursor is not
|
||||
// in the visible portion of the screen.
|
||||
@@ -2440,7 +2455,7 @@ pub fn setFontSize(self: *Surface, size: font.face.DesiredSize) !void {
|
||||
|
||||
// Notify our render thread of the new font stack. The renderer
|
||||
// MUST accept the new font grid and deref the old.
|
||||
_ = self.renderer_thread.mailbox.push(.{
|
||||
_ = self.renderer_thread.mailbox.push(global.io(), .{
|
||||
.font_grid = .{
|
||||
.grid = font_grid,
|
||||
.set = &self.app.font_grid_set,
|
||||
@@ -2530,8 +2545,8 @@ pub fn preeditCallback(self: *Surface, preedit_: ?[]const u8) !void {
|
||||
crash.sentry.thread_state = self.crashThreadState();
|
||||
defer crash.sentry.thread_state = null;
|
||||
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// We clear our selection when ANY OF:
|
||||
// 1. We have an existing preedit
|
||||
@@ -2566,7 +2581,7 @@ pub fn preeditCallback(self: *Surface, preedit_: ?[]const u8) !void {
|
||||
|
||||
// Allocate the codepoints slice
|
||||
const Codepoint = rendererpkg.State.Preedit.Codepoint;
|
||||
var codepoints: std.ArrayListUnmanaged(Codepoint) = .{};
|
||||
var codepoints: std.ArrayList(Codepoint) = .empty;
|
||||
defer codepoints.deinit(self.alloc);
|
||||
while (it.nextCodepoint()) |cp| {
|
||||
const width: usize = @intCast(unicode.table.get(cp).width);
|
||||
@@ -2697,8 +2712,8 @@ pub fn keyCallback(
|
||||
)) |v| return v;
|
||||
// If we allow KAM and KAM is enabled then we do nothing.
|
||||
if (self.config.vt_kam_allowed) {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
if (self.io.terminal.modes.get(.disable_keyboard)) return .consumed;
|
||||
}
|
||||
|
||||
@@ -2728,8 +2743,8 @@ pub fn keyCallback(
|
||||
{
|
||||
// Refresh our link state
|
||||
const pos = self.rt_surface.getCursorPos() catch break :mouse_mods;
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
self.mouseRefreshLinks(
|
||||
pos,
|
||||
self.posToViewport(pos.x, pos.y),
|
||||
@@ -2821,8 +2836,8 @@ pub fn keyCallback(
|
||||
// some data to send to the pty, then we move the viewport down to the
|
||||
// bottom. We also clear the selection for any key other then modifiers.
|
||||
if (!event.key.modifier()) {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
if (self.config.selection_clear_on_typing or
|
||||
event.key == .escape)
|
||||
@@ -3253,8 +3268,8 @@ fn encodeKey(
|
||||
}
|
||||
|
||||
fn encodeKeyOpts(self: *const Surface) input.key_encode.Options {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const t = &self.io.terminal;
|
||||
|
||||
var opts: input.key_encode.Options = .fromTerminal(t);
|
||||
@@ -3295,7 +3310,7 @@ pub fn occlusionCallback(self: *Surface, visible: bool) !void {
|
||||
crash.sentry.thread_state = self.crashThreadState();
|
||||
defer crash.sentry.thread_state = null;
|
||||
|
||||
_ = self.renderer_thread.mailbox.push(.{
|
||||
_ = self.renderer_thread.mailbox.push(global.io(), .{
|
||||
.visible = visible,
|
||||
}, .{ .forever = {} });
|
||||
try self.queueRender();
|
||||
@@ -3315,7 +3330,7 @@ pub fn focusCallback(self: *Surface, focused: bool) !void {
|
||||
self.focused = focused;
|
||||
|
||||
// Notify our render thread of the new state
|
||||
_ = self.renderer_thread.mailbox.push(.{
|
||||
_ = self.renderer_thread.mailbox.push(global.io(), .{
|
||||
.focus = focused,
|
||||
}, .{ .forever = {} });
|
||||
|
||||
@@ -3382,9 +3397,9 @@ pub fn focusCallback(self: *Surface, focused: bool) !void {
|
||||
|
||||
// Update the focus state and notify the terminal
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
self.io.terminal.flags.focused = focused;
|
||||
self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.unlock(global.io());
|
||||
self.queueIo(.{ .focused = focused }, .unlocked);
|
||||
}
|
||||
}
|
||||
@@ -3516,8 +3531,8 @@ pub fn scrollCallback(
|
||||
// log.info("SCROLL: delta_y={} delta_x={}", .{ y.delta, x.delta });
|
||||
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// If we have an active mouse reporting mode, clear the selection.
|
||||
// The selection can occur if the user uses the shift mod key to
|
||||
@@ -3717,8 +3732,8 @@ fn mouseShiftCapture(self: *const Surface, lock: bool) bool {
|
||||
.false, .true => {},
|
||||
}
|
||||
|
||||
if (lock) self.renderer_state.mutex.lock();
|
||||
defer if (lock) self.renderer_state.mutex.unlock();
|
||||
if (lock) self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer if (lock) self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// If the terminal explicitly requests it then we always allow it
|
||||
// since we processed never/always at this point.
|
||||
@@ -3739,8 +3754,8 @@ fn mouseShiftCapture(self: *const Surface, lock: bool) bool {
|
||||
/// Returns true if the mouse is currently captured by the terminal
|
||||
/// (i.e. reporting events).
|
||||
pub fn mouseCaptured(self: *Surface) bool {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
return self.io.terminal.flags.mouse_event != .none;
|
||||
}
|
||||
|
||||
@@ -3796,21 +3811,12 @@ pub fn mouseButtonCallback(
|
||||
|
||||
// If we are within the interval that the click would register
|
||||
// an increment then we do not extend the selection.
|
||||
if (std.time.Instant.now()) |now| {
|
||||
const click_time = self.mouse.selection_gesture.left_click_time orelse
|
||||
break :extend_selection;
|
||||
const since = now.since(click_time);
|
||||
if (since <= self.config.mouse_interval) {
|
||||
// Click interval very short, we may be increasing
|
||||
// click counts so we don't extend the selection.
|
||||
break :extend_selection;
|
||||
}
|
||||
} else |err| {
|
||||
// This is a weird behavior, I think either behavior is actually
|
||||
// fine. This failure should be exceptionally rare anyways.
|
||||
// My thinking here is that we can't be sure if we should extend
|
||||
// the selection or not so we just don't.
|
||||
log.warn("failed to get time, not extending selection err={}", .{err});
|
||||
const click_time = self.mouse.selection_gesture.left_click_time orelse
|
||||
break :extend_selection;
|
||||
const since = click_time.untilNow(global.io(), .awake);
|
||||
if (since.toNanoseconds() <= self.config.mouse_interval) {
|
||||
// Click interval very short, we may be increasing
|
||||
// click counts so we don't extend the selection.
|
||||
break :extend_selection;
|
||||
}
|
||||
|
||||
@@ -3821,8 +3827,8 @@ pub fn mouseButtonCallback(
|
||||
}
|
||||
|
||||
if (button == .left and action == .release) {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// The selection gesture tracks whether a press became a drag by
|
||||
// comparing the release cell to the original press cell. Resolve the
|
||||
@@ -3897,8 +3903,8 @@ pub fn mouseButtonCallback(
|
||||
|
||||
// Report mouse events if enabled
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
if (self.isMouseReporting()) report: {
|
||||
// If we have shift-pressed and we aren't allowed to capture it,
|
||||
// then we do not do a mouse report.
|
||||
@@ -3937,8 +3943,8 @@ pub fn mouseButtonCallback(
|
||||
// For left button clicks we always record some information for
|
||||
// selection/highlighting purposes.
|
||||
if (button == .left and action == .press) click: {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||
const screen: *terminal.Screen = self.renderer_state.terminal.screens.active;
|
||||
|
||||
@@ -3962,12 +3968,8 @@ pub fn mouseButtonCallback(
|
||||
break :pin pin;
|
||||
};
|
||||
|
||||
const time = std.time.Instant.now() catch |err| time: {
|
||||
log.err("error reading time, mouse multi-click won't work err={}", .{err});
|
||||
break :time null;
|
||||
};
|
||||
var press_selection = try self.mouse.selection_gesture.press(t, .{
|
||||
.time = time,
|
||||
.time = std.Io.Timestamp.now(global.io(), .awake),
|
||||
.pin = pin,
|
||||
.xpos = pos.x,
|
||||
.ypos = pos.y,
|
||||
@@ -4047,8 +4049,8 @@ pub fn mouseButtonCallback(
|
||||
// want to be careful in the future we can add a function to apprts
|
||||
// that let's us know.
|
||||
if (button == .right and action == .press) sel: {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// Get our viewport pin
|
||||
const screen: *terminal.Screen = self.renderer_state.terminal.screens.active;
|
||||
@@ -4119,8 +4121,8 @@ pub fn mouseButtonCallback(
|
||||
} else {
|
||||
// Pasting can trigger a lock grab in complete clipboard
|
||||
// request so we need to unlock.
|
||||
self.renderer_state.mutex.unlock();
|
||||
defer self.renderer_state.mutex.lock();
|
||||
self.renderer_state.mutex.unlock(global.io());
|
||||
defer self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
_ = try self.startClipboardRequest(.standard, .paste);
|
||||
|
||||
// We don't need to clear selection because we didn't have
|
||||
@@ -4134,8 +4136,8 @@ pub fn mouseButtonCallback(
|
||||
|
||||
// Pasting can trigger a lock grab in complete clipboard
|
||||
// request so we need to unlock.
|
||||
self.renderer_state.mutex.unlock();
|
||||
defer self.renderer_state.mutex.lock();
|
||||
self.renderer_state.mutex.unlock(global.io());
|
||||
defer self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
_ = try self.startClipboardRequest(.standard, .paste);
|
||||
},
|
||||
}
|
||||
@@ -4428,7 +4430,6 @@ fn openUrl(
|
||||
// apprts to handle this themselves.
|
||||
log.warn("apprt did not handle open URL action, falling back to default opener", .{});
|
||||
try internal_os.open(
|
||||
self.alloc,
|
||||
action.kind,
|
||||
action.url,
|
||||
);
|
||||
@@ -4474,8 +4475,8 @@ pub fn mousePressureCallback(
|
||||
if (self.mouse.click_state[left_idx] == .press and
|
||||
stage == .deep)
|
||||
select: {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
const sel = self.mouse.selection_gesture.deepPress(
|
||||
self.renderer_state.terminal,
|
||||
@@ -4540,8 +4541,8 @@ pub fn cursorPosCallback(
|
||||
try self.queueRender();
|
||||
}
|
||||
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// No mouse point so we don't highlight links
|
||||
self.renderer_state.mouse.point = null;
|
||||
@@ -4567,8 +4568,8 @@ pub fn cursorPosCallback(
|
||||
self.mouse.over_link = false;
|
||||
|
||||
// We are reading/writing state for the remainder
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// Update our mouse state. We set this to null initially because we only
|
||||
// want to set it when we're not selecting or doing any other mouse
|
||||
@@ -4824,8 +4825,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
|
||||
// CSI/ESC triggers a scroll.
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
self.scrollToBottom() catch |err| {
|
||||
log.warn("error scrolling to bottom err={}", .{err});
|
||||
};
|
||||
@@ -4851,8 +4852,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
|
||||
// Text triggers a scroll.
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
self.scrollToBottom() catch |err| {
|
||||
log.warn("error scrolling to bottom err={}", .{err});
|
||||
};
|
||||
@@ -4864,8 +4865,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
// in cursor keys mode. We're in "normal" mode if cursor
|
||||
// keys mode is NOT set.
|
||||
const normal = normal: {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// With the lock held, we must scroll to the bottom.
|
||||
// We always scroll to the bottom for these inputs.
|
||||
@@ -4884,8 +4885,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
},
|
||||
|
||||
.reset => {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
self.renderer_state.terminal.fullReset();
|
||||
},
|
||||
|
||||
@@ -4955,7 +4956,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
terminal.search.Thread.threadMain,
|
||||
.{&s.state},
|
||||
);
|
||||
s.thread.setName("search") catch {};
|
||||
s.thread.setName(global.io(), "search") catch {};
|
||||
|
||||
break :init s;
|
||||
};
|
||||
@@ -4968,6 +4969,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
}
|
||||
|
||||
_ = s.state.mailbox.push(
|
||||
global.io(),
|
||||
.{ .change_needle = try .init(
|
||||
self.alloc,
|
||||
text,
|
||||
@@ -4980,6 +4982,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
.navigate_search => |nav| {
|
||||
const s: *Search = if (self.search) |*s| s else return false;
|
||||
_ = s.state.mailbox.push(
|
||||
global.io(),
|
||||
.{ .select = switch (nav) {
|
||||
.next => .next,
|
||||
.previous => .prev,
|
||||
@@ -4990,8 +4993,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
},
|
||||
|
||||
.copy_to_clipboard => |format| {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
if (self.io.terminal.screens.active.selection) |sel| {
|
||||
try self.copySelectionToClipboards(
|
||||
@@ -5022,8 +5025,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
if (!self.mouse.over_link) return false;
|
||||
const pos = try self.rt_surface.getCursorPos();
|
||||
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
if (try self.linkAtPos(pos)) |link_info| {
|
||||
const url_text = switch (link_info.action) {
|
||||
.open => url_text: {
|
||||
@@ -5168,8 +5171,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
// alternate screen then clear screen does nothing so we want to
|
||||
// return false so the keybind can be unconsumed.
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
if (self.io.terminal.screens.active_key == .alternate) return false;
|
||||
}
|
||||
|
||||
@@ -5192,8 +5195,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
|
||||
.scroll_to_row => |n| {
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||
t.screens.active.scroll(.{ .row = n });
|
||||
}
|
||||
@@ -5203,8 +5206,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
|
||||
.scroll_to_selection => {
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const sel = self.io.terminal.screens.active.selection orelse return false;
|
||||
const tl = sel.topLeft(self.io.terminal.screens.active);
|
||||
self.io.terminal.screens.active.scroll(.{ .pin = tl });
|
||||
@@ -5442,8 +5445,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
),
|
||||
|
||||
.select_all => {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
const sel = self.io.terminal.screens.active.selectAll();
|
||||
if (sel) |s| {
|
||||
@@ -5564,7 +5567,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
.main => @panic("crash binding action, crashing intentionally"),
|
||||
|
||||
.render => {
|
||||
_ = self.renderer_thread.mailbox.push(.{ .crash = {} }, .{ .forever = {} });
|
||||
_ = self.renderer_thread.mailbox.push(global.io(), .{ .crash = {} }, .{ .forever = {} });
|
||||
self.queueRender() catch |err| {
|
||||
// Not a big deal if this fails.
|
||||
log.warn("failed to notify renderer of crash message err={}", .{err});
|
||||
@@ -5575,8 +5578,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
},
|
||||
|
||||
.adjust_selection => |direction| {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
const screen: *terminal.Screen = self.io.terminal.screens.active;
|
||||
const sel = if (screen.selection) |*sel| sel else {
|
||||
@@ -5672,23 +5675,24 @@ fn writeScreenFile(
|
||||
|
||||
// Open our scrollback file
|
||||
var file = try tmp_dir.dir.createFile(
|
||||
global.io(),
|
||||
filename,
|
||||
switch (builtin.os.tag) {
|
||||
.windows => .{},
|
||||
else => .{ .mode = 0o600 },
|
||||
else => .{ .permissions = .fromMode(0o600) },
|
||||
},
|
||||
);
|
||||
defer file.close();
|
||||
defer file.close(global.io());
|
||||
|
||||
// Screen.dumpString writes byte-by-byte, so buffer it
|
||||
var buf: [4096]u8 = undefined;
|
||||
var file_writer = file.writer(&buf);
|
||||
var file_writer = file.writer(global.io(), &buf);
|
||||
var buf_writer = &file_writer.interface;
|
||||
|
||||
// Write the scrollback contents. This requires a lock.
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// We only dump history if we have history. We still keep
|
||||
// the file and write the empty file to the pty so that this
|
||||
@@ -5751,7 +5755,11 @@ fn writeScreenFile(
|
||||
|
||||
// Get the final path
|
||||
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
const path = try tmp_dir.dir.realpath(filename, &path_buf);
|
||||
const path = path_buf[0..try tmp_dir.dir.realPathFile(
|
||||
global.io(),
|
||||
filename,
|
||||
&path_buf,
|
||||
)];
|
||||
|
||||
switch (write_screen.action) {
|
||||
.copy => {
|
||||
@@ -5849,8 +5857,8 @@ fn completeClipboardPaste(
|
||||
if (data.len == 0) return;
|
||||
|
||||
const encode_opts: input.paste.Options = encode_opts: {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
const opts: input.paste.Options = .fromTerminal(&self.io.terminal);
|
||||
|
||||
// If we have paste protection enabled, we detect unsafe pastes and return
|
||||
@@ -5970,12 +5978,12 @@ fn showDesktopNotification(self: *Surface, title: [:0]const u8, body: [:0]const
|
||||
// how fast identical notifications can be sent sequentially.
|
||||
const hash_algorithm = std.hash.Wyhash;
|
||||
|
||||
const now = try std.time.Instant.now();
|
||||
const now: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
|
||||
// Set a limit of one desktop notification per second so that the OS
|
||||
// doesn't kill us when we run out of resources.
|
||||
if (self.app.last_notification_time) |last| {
|
||||
if (now.since(last) < 1 * std.time.ns_per_s) {
|
||||
if (last.durationTo(now).toSeconds() < 1) {
|
||||
log.warn("rate limiting desktop notifications", .{});
|
||||
return;
|
||||
}
|
||||
@@ -5992,7 +6000,7 @@ fn showDesktopNotification(self: *Surface, title: [:0]const u8, body: [:0]const
|
||||
// notifications with identical content.
|
||||
if (self.app.last_notification_time) |last| {
|
||||
if (self.app.last_notification_digest == new_digest) {
|
||||
if (now.since(last) < 5 * std.time.ns_per_s) {
|
||||
if (last.durationTo(now).toSeconds() < 5) {
|
||||
log.warn("suppressing identical desktop notification", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const renderer = @import("../renderer.zig");
|
||||
const terminal = @import("../terminal/main.zig");
|
||||
const CoreSurface = @import("../Surface.zig");
|
||||
const lib = @import("../lib/main.zig");
|
||||
const compat_testing = @import("../lib/compat/testing.zig");
|
||||
|
||||
/// The target for an action. This is generally the thing that had focus
|
||||
/// while the action was made but the concept of "focus" is not guaranteed
|
||||
@@ -424,8 +425,11 @@ pub const Action = union(Key) {
|
||||
/// Sync with: ghostty_action_u
|
||||
pub const CValue = cvalue: {
|
||||
const key_fields = @typeInfo(Key).@"enum".fields;
|
||||
var union_fields: [key_fields.len]std.builtin.Type.UnionField = undefined;
|
||||
for (key_fields, 0..) |field, i| {
|
||||
var names: [key_fields.len][]const u8 = undefined;
|
||||
var types: [key_fields.len]type = undefined;
|
||||
var attrs: [key_fields.len]std.builtin.Type.UnionField.Attributes = undefined;
|
||||
|
||||
for (key_fields, &names, &types, &attrs) |field, *name, *ty, *attr| {
|
||||
const action = @unionInit(Action, field.name, undefined);
|
||||
const Type = t: {
|
||||
const Type = @TypeOf(@field(action, field.name));
|
||||
@@ -434,19 +438,12 @@ pub const Action = union(Key) {
|
||||
break :t Type;
|
||||
};
|
||||
|
||||
union_fields[i] = .{
|
||||
.name = field.name,
|
||||
.type = Type,
|
||||
.alignment = @alignOf(Type),
|
||||
};
|
||||
name.* = field.name;
|
||||
ty.* = Type;
|
||||
attr.* = .{ .@"align" = @alignOf(Type) };
|
||||
}
|
||||
|
||||
break :cvalue @Type(.{ .@"union" = .{
|
||||
.layout = .@"extern",
|
||||
.tag_type = null,
|
||||
.fields = &union_fields,
|
||||
.decls = &.{},
|
||||
} });
|
||||
break :cvalue @Union(.@"extern", null, &names, &types, &attrs);
|
||||
};
|
||||
|
||||
/// Sync with: ghostty_action_s
|
||||
@@ -713,7 +710,7 @@ pub const SetTitle = struct {
|
||||
pub fn format(
|
||||
value: @This(),
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
_: std.fmt.Options,
|
||||
writer: *std.Io.Writer,
|
||||
) !void {
|
||||
try writer.print("{s}{{ {s} }}", .{ @typeName(@This()), value.title });
|
||||
@@ -737,7 +734,7 @@ pub const Pwd = struct {
|
||||
pub fn format(
|
||||
value: @This(),
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
_: std.fmt.Options,
|
||||
writer: *std.Io.Writer,
|
||||
) !void {
|
||||
try writer.print("{s}{{ {s} }}", .{ @typeName(@This()), value.pwd });
|
||||
@@ -765,7 +762,7 @@ pub const DesktopNotification = struct {
|
||||
pub fn format(
|
||||
value: @This(),
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
_: std.fmt.Options,
|
||||
writer: *std.Io.Writer,
|
||||
) !void {
|
||||
try writer.print("{s}{{ title: {s}, body: {s} }}", .{
|
||||
@@ -1008,5 +1005,5 @@ pub const SearchSelected = struct {
|
||||
};
|
||||
|
||||
test {
|
||||
_ = std.testing.refAllDeclsRecursive(@This());
|
||||
_ = compat_testing.refAllDeclsRecursive(@This());
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ const Allocator = std.mem.Allocator;
|
||||
const objc = @import("objc");
|
||||
const apprt = @import("../apprt.zig");
|
||||
const font = @import("../font/main.zig");
|
||||
const global = @import("../global.zig");
|
||||
const input = @import("../input.zig");
|
||||
const internal_os = @import("../os/main.zig");
|
||||
const renderer = @import("../renderer.zig");
|
||||
@@ -333,7 +334,7 @@ pub const App = struct {
|
||||
_: apprt.ipc.Target,
|
||||
comptime action: apprt.ipc.Action.Key,
|
||||
_: apprt.ipc.Action.Value(action),
|
||||
) (Allocator.Error || std.posix.WriteError || apprt.ipc.Errors)!bool {
|
||||
) (Allocator.Error || apprt.ipc.Errors)!bool {
|
||||
switch (action) {
|
||||
.new_window => return false,
|
||||
.toggle_quick_terminal => return false,
|
||||
@@ -372,7 +373,7 @@ pub const Platform = union(PlatformTag) {
|
||||
|
||||
/// Initialize a Platform a tag and configuration from the C ABI.
|
||||
pub fn init(tag_int: c_int, c_platform: C) !Platform {
|
||||
const tag = try std.meta.intToEnum(PlatformTag, tag_int);
|
||||
const tag = std.enums.fromInt(PlatformTag, tag_int) orelse return error.InvalidEnumTag;
|
||||
return switch (tag) {
|
||||
.macos => if (MacOS != void) macos: {
|
||||
const config = c_platform.macos;
|
||||
@@ -490,16 +491,16 @@ pub const Surface = struct {
|
||||
if (opts.working_directory) |c_wd| {
|
||||
const wd = std.mem.sliceTo(c_wd, 0);
|
||||
if (wd.len > 0) wd: {
|
||||
var dir = std.fs.openDirAbsolute(wd, .{}) catch |err| {
|
||||
var dir = std.Io.Dir.openDirAbsolute(global.io(), wd, .{}) catch |err| {
|
||||
log.warn(
|
||||
"error opening requested working directory dir={s} err={}",
|
||||
.{ wd, err },
|
||||
);
|
||||
break :wd;
|
||||
};
|
||||
defer dir.close();
|
||||
defer dir.close(global.io());
|
||||
|
||||
const stat = dir.stat() catch |err| {
|
||||
const stat = dir.stat(global.io()) catch |err| {
|
||||
log.warn(
|
||||
"failed to stat requested working directory dir={s} err={}",
|
||||
.{ wd, err },
|
||||
@@ -950,32 +951,32 @@ pub const Surface = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn defaultTermioEnv(self: *const Surface) !std.process.EnvMap {
|
||||
const alloc = self.app.core_app.alloc;
|
||||
var env = try internal_os.getEnvMap(alloc);
|
||||
pub fn defaultTermioEnv(self: *const Surface) !std.process.Environ.Map {
|
||||
_ = self;
|
||||
var env = try global.environMap();
|
||||
errdefer env.deinit();
|
||||
|
||||
if (comptime builtin.target.os.tag.isDarwin()) {
|
||||
if (env.get("__XCODE_BUILT_PRODUCTS_DIR_PATHS") != null) {
|
||||
env.remove("__XCODE_BUILT_PRODUCTS_DIR_PATHS");
|
||||
env.remove("__XPC_DYLD_LIBRARY_PATH");
|
||||
env.remove("DYLD_FRAMEWORK_PATH");
|
||||
env.remove("DYLD_INSERT_LIBRARIES");
|
||||
env.remove("DYLD_LIBRARY_PATH");
|
||||
env.remove("LD_LIBRARY_PATH");
|
||||
env.remove("SECURITYSESSIONID");
|
||||
env.remove("XPC_SERVICE_NAME");
|
||||
_ = env.orderedRemove("__XCODE_BUILT_PRODUCTS_DIR_PATHS");
|
||||
_ = env.orderedRemove("__XPC_DYLD_LIBRARY_PATH");
|
||||
_ = env.orderedRemove("DYLD_FRAMEWORK_PATH");
|
||||
_ = env.orderedRemove("DYLD_INSERT_LIBRARIES");
|
||||
_ = env.orderedRemove("DYLD_LIBRARY_PATH");
|
||||
_ = env.orderedRemove("LD_LIBRARY_PATH");
|
||||
_ = env.orderedRemove("SECURITYSESSIONID");
|
||||
_ = env.orderedRemove("XPC_SERVICE_NAME");
|
||||
}
|
||||
|
||||
// Remove this so that running `ghostty` within Ghostty works.
|
||||
env.remove("GHOSTTY_MAC_LAUNCH_SOURCE");
|
||||
_ = env.orderedRemove("GHOSTTY_MAC_LAUNCH_SOURCE");
|
||||
|
||||
// If we were launched from the desktop then we want to
|
||||
// remove the LANGUAGE env var so that we don't inherit
|
||||
// our translation settings for Ghostty. If we aren't from
|
||||
// the desktop then we didn't set our LANGUAGE var so we
|
||||
// don't need to remove it.
|
||||
if (internal_os.launchedFromDesktop()) env.remove("LANGUAGE");
|
||||
if (internal_os.launchedFromDesktop()) _ = env.orderedRemove("LANGUAGE");
|
||||
}
|
||||
|
||||
return env;
|
||||
@@ -1000,7 +1001,7 @@ pub const Inspector = struct {
|
||||
content_scale: f64 = 1,
|
||||
|
||||
/// Our previous instant used to calculate delta time for animations.
|
||||
instant: ?std.time.Instant = null,
|
||||
instant: ?std.Io.Timestamp = null,
|
||||
|
||||
const Backend = enum {
|
||||
metal,
|
||||
@@ -1229,9 +1230,9 @@ pub const Inspector = struct {
|
||||
const io: *cimgui.c.ImGuiIO = cimgui.c.ImGui_GetIO();
|
||||
|
||||
// Determine our delta time
|
||||
const now = try std.time.Instant.now();
|
||||
const now: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
io.DeltaTime = if (self.instant) |prev| delta: {
|
||||
const since_ns: f64 = @floatFromInt(now.since(prev));
|
||||
const since_ns: f64 = @floatFromInt(prev.durationTo(now).toNanoseconds());
|
||||
const ns_per_s: f64 = @floatFromInt(std.time.ns_per_s);
|
||||
const since_s: f32 = @floatCast(since_ns / ns_per_s);
|
||||
break :delta @max(0.00001, since_s);
|
||||
@@ -1242,8 +1243,6 @@ pub const Inspector = struct {
|
||||
|
||||
// C API
|
||||
pub const CAPI = struct {
|
||||
const global = &@import("../global.zig").state;
|
||||
|
||||
/// This is the same as Surface.KeyEvent but this is the raw C API version.
|
||||
const KeyEvent = extern struct {
|
||||
action: input.Action,
|
||||
@@ -1300,7 +1299,7 @@ pub const CAPI = struct {
|
||||
|
||||
pub fn deinit(self: *Text) void {
|
||||
if (self.text) |ptr| {
|
||||
global.alloc.free(ptr[0..self.text_len :0]);
|
||||
global.alloc().free(ptr[0..self.text_len :0]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1410,12 +1409,12 @@ pub const CAPI = struct {
|
||||
opts: *const apprt.runtime.App.Options,
|
||||
config: *const Config,
|
||||
) !*App {
|
||||
const core_app = try CoreApp.create(global.alloc);
|
||||
const core_app = try CoreApp.create(global.alloc());
|
||||
errdefer core_app.destroy();
|
||||
|
||||
// Create our runtime app
|
||||
var app = try global.alloc.create(App);
|
||||
errdefer global.alloc.destroy(app);
|
||||
var app = try global.alloc().create(App);
|
||||
errdefer global.alloc().destroy(app);
|
||||
try app.init(core_app, config, opts.*);
|
||||
errdefer app.terminate();
|
||||
|
||||
@@ -1438,7 +1437,7 @@ pub const CAPI = struct {
|
||||
export fn ghostty_app_free(v: *App) void {
|
||||
const core_app = v.core_app;
|
||||
v.terminate();
|
||||
global.alloc.destroy(v);
|
||||
global.alloc().destroy(v);
|
||||
core_app.destroy();
|
||||
}
|
||||
|
||||
@@ -1520,13 +1519,7 @@ pub const CAPI = struct {
|
||||
|
||||
/// Update the color scheme of the app.
|
||||
export fn ghostty_app_set_color_scheme(v: *App, scheme_raw: c_int) void {
|
||||
const scheme = std.meta.intToEnum(apprt.ColorScheme, scheme_raw) catch {
|
||||
log.warn(
|
||||
"invalid color scheme to ghostty_surface_set_color_scheme value={}",
|
||||
.{scheme_raw},
|
||||
);
|
||||
return;
|
||||
};
|
||||
const scheme = std.enums.fromInt(apprt.ColorScheme, scheme_raw) orelse return;
|
||||
|
||||
v.core_app.colorSchemeEvent(v, scheme) catch |err| {
|
||||
log.err("error setting color scheme err={}", .{err});
|
||||
@@ -1612,8 +1605,8 @@ pub const CAPI = struct {
|
||||
result: *Text,
|
||||
) bool {
|
||||
const core_surface = &surface.core_surface;
|
||||
core_surface.renderer_state.mutex.lock();
|
||||
defer core_surface.renderer_state.mutex.unlock();
|
||||
core_surface.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer core_surface.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// If we don't have a selection, do nothing.
|
||||
const core_sel = core_surface.io.terminal.screens.active.selection orelse return false;
|
||||
@@ -1632,8 +1625,8 @@ pub const CAPI = struct {
|
||||
sel: Selection,
|
||||
result: *Text,
|
||||
) bool {
|
||||
surface.core_surface.renderer_state.mutex.lock();
|
||||
defer surface.core_surface.renderer_state.mutex.unlock();
|
||||
surface.core_surface.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer surface.core_surface.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
const core_sel = sel.core(
|
||||
surface.core_surface.renderer_state.terminal.screens.active,
|
||||
@@ -1651,7 +1644,7 @@ pub const CAPI = struct {
|
||||
|
||||
// Get our text directly from the core surface.
|
||||
const text = core_surface.dumpTextLocked(
|
||||
global.alloc,
|
||||
global.alloc(),
|
||||
core_sel,
|
||||
) catch |err| {
|
||||
log.warn("error reading text err={}", .{err});
|
||||
@@ -1730,14 +1723,7 @@ pub const CAPI = struct {
|
||||
|
||||
/// Update the color scheme of the surface.
|
||||
export fn ghostty_surface_set_color_scheme(surface: *Surface, scheme_raw: c_int) void {
|
||||
const scheme = std.meta.intToEnum(apprt.ColorScheme, scheme_raw) catch {
|
||||
log.warn(
|
||||
"invalid color scheme to ghostty_surface_set_color_scheme value={}",
|
||||
.{scheme_raw},
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
const scheme = std.enums.fromInt(apprt.ColorScheme, scheme_raw) orelse return;
|
||||
surface.colorSchemeCallback(scheme);
|
||||
}
|
||||
|
||||
@@ -1891,17 +1877,7 @@ pub const CAPI = struct {
|
||||
stage_raw: u32,
|
||||
pressure: f64,
|
||||
) void {
|
||||
const stage = std.meta.intToEnum(
|
||||
input.MousePressureStage,
|
||||
stage_raw,
|
||||
) catch {
|
||||
log.warn(
|
||||
"invalid mouse pressure stage value={}",
|
||||
.{stage_raw},
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
const stage = std.enums.fromInt(input.MousePressureStage, stage_raw) orelse return;
|
||||
surface.mousePressureCallback(stage, pressure);
|
||||
}
|
||||
|
||||
@@ -2134,6 +2110,7 @@ pub const CAPI = struct {
|
||||
export fn ghostty_surface_set_display_id(ptr: *Surface, display_id: u32) void {
|
||||
const surface = &ptr.core_surface;
|
||||
_ = surface.renderer_thread.mailbox.push(
|
||||
global.io(),
|
||||
.{ .macos_display_id = display_id },
|
||||
.{ .forever = {} },
|
||||
);
|
||||
@@ -2157,8 +2134,8 @@ pub const CAPI = struct {
|
||||
// read the font face. It should not be deferred since
|
||||
// we're loading the primary face.
|
||||
const grid = ptr.core_surface.renderer.font_grid;
|
||||
grid.lock.lockShared();
|
||||
defer grid.lock.unlockShared();
|
||||
grid.lock.lockSharedUncancelable(global.io());
|
||||
defer grid.lock.unlockShared(global.io());
|
||||
|
||||
const collection = &grid.resolver.collection;
|
||||
const face = collection.getFace(.{}) catch return null;
|
||||
@@ -2195,8 +2172,8 @@ pub const CAPI = struct {
|
||||
result: *Text,
|
||||
) bool {
|
||||
const surface = &ptr.core_surface;
|
||||
surface.renderer_state.mutex.lock();
|
||||
defer surface.renderer_state.mutex.unlock();
|
||||
surface.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer surface.renderer_state.mutex.unlock(global.io());
|
||||
|
||||
// Get our word selection
|
||||
const sel = sel: {
|
||||
|
||||
@@ -94,7 +94,7 @@ pub fn setClipboard(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn defaultTermioEnv(self: *Self) !std.process.EnvMap {
|
||||
pub fn defaultTermioEnv(self: *Self) !std.process.Environ.Map {
|
||||
return try self.surface.defaultTermioEnv();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,16 @@ const std = @import("std");
|
||||
// Ghostty, we need to import `adwaita.h` directly to ensure that the version
|
||||
// macros match the version of `libadwaita` that we are building/linking
|
||||
// against.
|
||||
const c = @cImport({
|
||||
@cInclude("adwaita.h");
|
||||
});
|
||||
const adw_c = @import("adw_c");
|
||||
|
||||
const adw = @import("adw");
|
||||
|
||||
const log = std.log.scoped(.gtk);
|
||||
|
||||
pub const comptime_version: std.SemanticVersion = .{
|
||||
.major = c.ADW_MAJOR_VERSION,
|
||||
.minor = c.ADW_MINOR_VERSION,
|
||||
.patch = c.ADW_MICRO_VERSION,
|
||||
.major = adw_c.ADW_MAJOR_VERSION,
|
||||
.minor = adw_c.ADW_MINOR_VERSION,
|
||||
.patch = adw_c.ADW_MICRO_VERSION,
|
||||
};
|
||||
|
||||
pub fn getRuntimeVersion() std.SemanticVersion {
|
||||
@@ -89,14 +87,14 @@ test "versionAtLeast" {
|
||||
|
||||
const funs = &.{ atLeast, runtimeAtLeast };
|
||||
inline for (funs) |fun| {
|
||||
try testing.expect(fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION));
|
||||
try testing.expect(!fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION + 1));
|
||||
try testing.expect(!fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION + 1, c.ADW_MICRO_VERSION));
|
||||
try testing.expect(!fun(c.ADW_MAJOR_VERSION + 1, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION));
|
||||
try testing.expect(fun(c.ADW_MAJOR_VERSION - 1, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION));
|
||||
try testing.expect(fun(c.ADW_MAJOR_VERSION - 1, c.ADW_MINOR_VERSION + 1, c.ADW_MICRO_VERSION));
|
||||
try testing.expect(fun(c.ADW_MAJOR_VERSION - 1, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION + 1));
|
||||
try testing.expect(fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION - 1, c.ADW_MICRO_VERSION + 1));
|
||||
try testing.expect(fun(adw_c.ADW_MAJOR_VERSION, adw_c.ADW_MINOR_VERSION, adw_c.ADW_MICRO_VERSION));
|
||||
try testing.expect(!fun(adw_c.ADW_MAJOR_VERSION, adw_c.ADW_MINOR_VERSION, adw_c.ADW_MICRO_VERSION + 1));
|
||||
try testing.expect(!fun(adw_c.ADW_MAJOR_VERSION, adw_c.ADW_MINOR_VERSION + 1, adw_c.ADW_MICRO_VERSION));
|
||||
try testing.expect(!fun(adw_c.ADW_MAJOR_VERSION + 1, adw_c.ADW_MINOR_VERSION, adw_c.ADW_MICRO_VERSION));
|
||||
try testing.expect(fun(adw_c.ADW_MAJOR_VERSION - 1, adw_c.ADW_MINOR_VERSION, adw_c.ADW_MICRO_VERSION));
|
||||
try testing.expect(fun(adw_c.ADW_MAJOR_VERSION - 1, adw_c.ADW_MINOR_VERSION + 1, adw_c.ADW_MICRO_VERSION));
|
||||
try testing.expect(fun(adw_c.ADW_MAJOR_VERSION - 1, adw_c.ADW_MINOR_VERSION, adw_c.ADW_MICRO_VERSION + 1));
|
||||
try testing.expect(fun(adw_c.ADW_MAJOR_VERSION, adw_c.ADW_MINOR_VERSION - 1, adw_c.ADW_MICRO_VERSION + 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
//! Example: blueprint.zig 1 5 output.ui input.blp
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub const c = @cImport({
|
||||
@cInclude("adwaita.h");
|
||||
});
|
||||
const adw_c = @import("adw_c");
|
||||
|
||||
pub const blueprint_compiler_help =
|
||||
\\
|
||||
@@ -26,23 +23,24 @@ pub const blueprint_compiler_help =
|
||||
;
|
||||
|
||||
const adwaita_version = std.SemanticVersion{
|
||||
.major = c.ADW_MAJOR_VERSION,
|
||||
.minor = c.ADW_MINOR_VERSION,
|
||||
.patch = c.ADW_MICRO_VERSION,
|
||||
.major = adw_c.ADW_MAJOR_VERSION,
|
||||
.minor = adw_c.ADW_MINOR_VERSION,
|
||||
.patch = adw_c.ADW_MICRO_VERSION,
|
||||
};
|
||||
|
||||
const required_blueprint_version = std.SemanticVersion{
|
||||
.major = 0,
|
||||
.minor = 16,
|
||||
.patch = 0,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer _ = debug_allocator.deinit();
|
||||
const alloc = debug_allocator.allocator();
|
||||
|
||||
// Get our args
|
||||
var it = try std.process.argsWithAllocator(alloc);
|
||||
var it = try init.minimal.args.iterateAllocator(alloc);
|
||||
defer it.deinit();
|
||||
_ = it.next(); // Skip argv0
|
||||
const arg_major = it.next() orelse return error.NoMajorVersion;
|
||||
@@ -63,51 +61,37 @@ pub fn main() !void {
|
||||
\\compile this blueprint. Please install it, ensure that it is
|
||||
\\available on your PATH, and then retry building Ghostty.
|
||||
, .{required_adwaita_version});
|
||||
std.posix.exit(1);
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
// Version checks
|
||||
{
|
||||
var stdout: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer stdout.deinit(alloc);
|
||||
var stderr: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer stderr.deinit(alloc);
|
||||
|
||||
var blueprint_compiler = std.process.Child.init(
|
||||
&.{
|
||||
"blueprint-compiler",
|
||||
"--version",
|
||||
},
|
||||
alloc,
|
||||
);
|
||||
blueprint_compiler.stdout_behavior = .Pipe;
|
||||
blueprint_compiler.stderr_behavior = .Pipe;
|
||||
try blueprint_compiler.spawn();
|
||||
try blueprint_compiler.collectOutput(
|
||||
alloc,
|
||||
&stdout,
|
||||
&stderr,
|
||||
std.math.maxInt(u16),
|
||||
);
|
||||
const term = blueprint_compiler.wait() catch |err| switch (err) {
|
||||
const blueprint_compiler = std.process.run(alloc, init.io, .{
|
||||
.argv = &.{ "blueprint-compiler", "--version" },
|
||||
}) catch |err| switch (err) {
|
||||
error.FileNotFound => {
|
||||
std.debug.print(
|
||||
\\`blueprint-compiler` not found.
|
||||
++ blueprint_compiler_help,
|
||||
.{required_blueprint_version},
|
||||
);
|
||||
std.posix.exit(1);
|
||||
std.process.exit(1);
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
switch (term) {
|
||||
.Exited => |rc| if (rc != 0) std.process.exit(1),
|
||||
defer {
|
||||
alloc.free(blueprint_compiler.stdout);
|
||||
alloc.free(blueprint_compiler.stderr);
|
||||
}
|
||||
|
||||
switch (blueprint_compiler.term) {
|
||||
.exited => |rc| if (rc != 0) std.process.exit(1),
|
||||
else => std.process.exit(1),
|
||||
}
|
||||
|
||||
const version = try std.SemanticVersion.parse(std.mem.trim(
|
||||
u8,
|
||||
stdout.items,
|
||||
blueprint_compiler.stdout,
|
||||
&std.ascii.whitespace,
|
||||
));
|
||||
if (version.order(required_blueprint_version) == .lt) {
|
||||
@@ -116,57 +100,45 @@ pub fn main() !void {
|
||||
++ blueprint_compiler_help,
|
||||
.{required_blueprint_version},
|
||||
);
|
||||
std.posix.exit(1);
|
||||
std.process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Compilation
|
||||
{
|
||||
var stdout: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer stdout.deinit(alloc);
|
||||
var stderr: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer stderr.deinit(alloc);
|
||||
|
||||
var blueprint_compiler = std.process.Child.init(
|
||||
&.{
|
||||
const blueprint_compiler = std.process.run(alloc, init.io, .{
|
||||
.argv = &.{
|
||||
"blueprint-compiler",
|
||||
"compile",
|
||||
"--output",
|
||||
output,
|
||||
input,
|
||||
},
|
||||
alloc,
|
||||
);
|
||||
blueprint_compiler.stdout_behavior = .Pipe;
|
||||
blueprint_compiler.stderr_behavior = .Pipe;
|
||||
try blueprint_compiler.spawn();
|
||||
try blueprint_compiler.collectOutput(
|
||||
alloc,
|
||||
&stdout,
|
||||
&stderr,
|
||||
std.math.maxInt(u16),
|
||||
);
|
||||
const term = blueprint_compiler.wait() catch |err| switch (err) {
|
||||
}) catch |err| switch (err) {
|
||||
error.FileNotFound => {
|
||||
std.debug.print(
|
||||
\\`blueprint-compiler` not found.
|
||||
++ blueprint_compiler_help,
|
||||
.{required_blueprint_version},
|
||||
);
|
||||
std.posix.exit(1);
|
||||
std.process.exit(1);
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
defer {
|
||||
alloc.free(blueprint_compiler.stdout);
|
||||
alloc.free(blueprint_compiler.stderr);
|
||||
}
|
||||
|
||||
switch (term) {
|
||||
.Exited => |rc| {
|
||||
switch (blueprint_compiler.term) {
|
||||
.exited => |rc| {
|
||||
if (rc != 0) {
|
||||
std.debug.print("{s}", .{stderr.items});
|
||||
std.debug.print("{s}", .{blueprint_compiler.stderr});
|
||||
std.process.exit(1);
|
||||
}
|
||||
},
|
||||
else => {
|
||||
std.debug.print("{s}", .{stderr.items});
|
||||
std.debug.print("{s}", .{blueprint_compiler.stderr});
|
||||
std.process.exit(1);
|
||||
},
|
||||
}
|
||||
|
||||
@@ -122,18 +122,17 @@ pub fn blueprint(comptime bp: Blueprint) [:0]const u8 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||
defer _ = debug_allocator.deinit();
|
||||
const alloc = debug_allocator.allocator();
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
const alloc = init.arena.allocator();
|
||||
|
||||
// Collect the UI files that are passed in as arguments.
|
||||
var ui_files: std.ArrayListUnmanaged([]const u8) = .empty;
|
||||
var ui_files: std.ArrayList([]const u8) = .empty;
|
||||
defer {
|
||||
for (ui_files.items) |item| alloc.free(item);
|
||||
ui_files.deinit(alloc);
|
||||
}
|
||||
var it = try std.process.argsWithAllocator(alloc);
|
||||
|
||||
var it = try init.minimal.args.iterateAllocator(alloc);
|
||||
defer it.deinit();
|
||||
while (it.next()) |arg| {
|
||||
if (!std.mem.endsWith(u8, arg, ".ui")) continue;
|
||||
@@ -144,7 +143,7 @@ pub fn main() !void {
|
||||
}
|
||||
|
||||
var buf: [4096]u8 = undefined;
|
||||
var stdout = std.fs.File.stdout().writer(&buf);
|
||||
var stdout = std.Io.File.stdout().writer(init.io, &buf);
|
||||
const writer = &stdout.interface;
|
||||
try writer.writeAll(
|
||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -152,8 +151,8 @@ pub fn main() !void {
|
||||
\\
|
||||
);
|
||||
|
||||
try genRoot(writer);
|
||||
try genIcons(writer);
|
||||
try genRoot(init.io, writer);
|
||||
try genIcons(init.io, writer);
|
||||
try genUi(alloc, writer, &ui_files);
|
||||
|
||||
try writer.writeAll(
|
||||
@@ -167,19 +166,19 @@ pub fn main() !void {
|
||||
/// Generate the icon resources. This works by looking up all the icons
|
||||
/// specified by `icon_sizes` in `images/icons/`. They are asserted to exist
|
||||
/// by trying to access the file.
|
||||
fn genIcons(writer: *std.Io.Writer) !void {
|
||||
fn genIcons(io: std.Io, writer: *std.Io.Writer) !void {
|
||||
try writer.print(
|
||||
\\ <gresource prefix="{s}/icons">
|
||||
\\
|
||||
, .{build_info.resource_path});
|
||||
|
||||
const cwd = std.fs.cwd();
|
||||
const cwd: std.Io.Dir = .cwd();
|
||||
inline for (icon_sizes) |size| {
|
||||
// 1x
|
||||
{
|
||||
const alias = std.fmt.comptimePrint("{d}x{d}", .{ size, size });
|
||||
const source = std.fmt.comptimePrint("images/gnome/{d}.png", .{size});
|
||||
try cwd.access(source, .{});
|
||||
try cwd.access(io, source, .{});
|
||||
try writer.print(
|
||||
\\ <file alias="{s}/apps/{s}.png">{s}</file>
|
||||
\\
|
||||
@@ -192,7 +191,7 @@ fn genIcons(writer: *std.Io.Writer) !void {
|
||||
{
|
||||
const alias = std.fmt.comptimePrint("{d}x{d}@2", .{ size, size });
|
||||
const source = std.fmt.comptimePrint("images/gnome/{d}.png", .{size * 2});
|
||||
try cwd.access(source, .{});
|
||||
try cwd.access(io, source, .{});
|
||||
try writer.print(
|
||||
\\ <file alias="{s}/apps/{s}.png">{s}</file>
|
||||
\\
|
||||
@@ -209,19 +208,19 @@ fn genIcons(writer: *std.Io.Writer) !void {
|
||||
}
|
||||
|
||||
/// Generate the resources at the root prefix.
|
||||
fn genRoot(writer: *std.Io.Writer) !void {
|
||||
fn genRoot(io: std.Io, writer: *std.Io.Writer) !void {
|
||||
try writer.print(
|
||||
\\ <gresource prefix="{s}">
|
||||
\\
|
||||
, .{build_info.resource_path});
|
||||
|
||||
const cwd = std.fs.cwd();
|
||||
const cwd: std.Io.Dir = .cwd();
|
||||
inline for (css) |name| {
|
||||
const source = std.fmt.comptimePrint(
|
||||
"{s}/{s}",
|
||||
.{ css_path, name },
|
||||
);
|
||||
try cwd.access(source, .{});
|
||||
try cwd.access(io, source, .{});
|
||||
try writer.print(
|
||||
\\ <file compressed="true" alias="{s}">{s}</file>
|
||||
\\
|
||||
@@ -242,7 +241,7 @@ fn genRoot(writer: *std.Io.Writer) !void {
|
||||
fn genUi(
|
||||
alloc: Allocator,
|
||||
writer: *std.Io.Writer,
|
||||
files: *const std.ArrayListUnmanaged([]const u8),
|
||||
files: *const std.ArrayList([]const u8),
|
||||
) !void {
|
||||
try writer.print(
|
||||
\\ <gresource prefix="{s}/ui">
|
||||
|
||||
@@ -145,16 +145,24 @@ pub fn Common(
|
||||
/// as the virtual method but the self parameter points to the
|
||||
/// target instead of the original class.
|
||||
fn ImplementFunc(comptime T: type) type {
|
||||
var params: [fn_info.params.len]std.builtin.Type.Fn.Param = undefined;
|
||||
@memcpy(¶ms, fn_info.params);
|
||||
params[0].type = *ClassInstance(T);
|
||||
return @Type(.{ .@"fn" = .{
|
||||
.calling_convention = fn_info.calling_convention,
|
||||
.is_generic = fn_info.is_generic,
|
||||
.is_var_args = fn_info.is_var_args,
|
||||
.return_type = fn_info.return_type,
|
||||
.params = ¶ms,
|
||||
} });
|
||||
var types: [fn_info.params.len]type = undefined;
|
||||
var attrs: [fn_info.params.len]std.builtin.Type.Fn.Param.Attributes = undefined;
|
||||
|
||||
for (fn_info.params, &types, &attrs) |info, *ty, *attr| {
|
||||
ty.* = info.type.?;
|
||||
attr.* = .{ .@"noalias" = info.is_noalias };
|
||||
}
|
||||
types[0] = *ClassInstance(T);
|
||||
|
||||
return @Fn(
|
||||
&types,
|
||||
&attrs,
|
||||
fn_info.return_type.?,
|
||||
.{
|
||||
.@"callconv" = fn_info.calling_convention,
|
||||
.varargs = fn_info.is_var_args,
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const assert = @import("../../../quirks.zig").inlineAssert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@@ -10,16 +11,17 @@ const gtk = @import("gtk");
|
||||
|
||||
const build_config = @import("../../../build_config.zig");
|
||||
const build_info = @import("../build/info.zig");
|
||||
const state = &@import("../../../global.zig").state;
|
||||
const global = @import("../../../global.zig");
|
||||
const i18n = @import("../../../os/main.zig").i18n;
|
||||
const apprt = @import("../../../apprt.zig");
|
||||
const CoreApp = @import("../../../App.zig");
|
||||
const compat_file = @import("../../../lib/compat/file.zig");
|
||||
const configpkg = @import("../../../config.zig");
|
||||
const input = @import("../../../input.zig");
|
||||
const internal_os = @import("../../../os/main.zig");
|
||||
const systemd = @import("../../../os/systemd.zig");
|
||||
const terminal = @import("../../../terminal/main.zig");
|
||||
const xev = @import("../../../global.zig").xev;
|
||||
const xev = global.xev;
|
||||
const Binding = @import("../../../input.zig").Binding;
|
||||
const CoreConfig = configpkg.Config;
|
||||
const CoreSurface = @import("../../../Surface.zig");
|
||||
@@ -45,6 +47,8 @@ const OpenURI = @import("../portal.zig").OpenURI;
|
||||
|
||||
const log = std.log.scoped(.gtk_ghostty_application);
|
||||
|
||||
extern "c" fn setenv(name: ?[*]const u8, value: ?[*]const u8, overwrite: c_int) c_int;
|
||||
|
||||
/// Function used to funnel GLib/GObject/GTK log messages into Zig's logging
|
||||
/// system rather than just getting dumped directly to stderr.
|
||||
fn glibLogWriterFunction(
|
||||
@@ -271,15 +275,17 @@ pub const Application = extern struct {
|
||||
};
|
||||
defer config.deinit();
|
||||
|
||||
// Set the old language,
|
||||
const saved_language: ?[:0]const u8 = saved_language: {
|
||||
const old_language = old_language: {
|
||||
const result = (internal_os.getenv(alloc, "LANG") catch break :old_language null) orelse break :old_language null;
|
||||
defer result.deinit(alloc);
|
||||
break :old_language alloc.dupeZ(u8, result.value) catch break :old_language null;
|
||||
const lang = global.environ().getPosix("LANG") orelse break :old_language null;
|
||||
break :old_language alloc.dupeSentinel(u8, @ptrCast(lang), 0) catch null;
|
||||
};
|
||||
|
||||
if (config.language) |language| _ = internal_os.setenv("LANG", language);
|
||||
|
||||
if (config.language) |language| {
|
||||
// Override LANG if we need to (sync global environs if so)
|
||||
_ = setenv("LANG", @ptrCast(language), 1);
|
||||
global.syncEnviron();
|
||||
}
|
||||
break :saved_language old_language;
|
||||
};
|
||||
|
||||
@@ -294,7 +300,7 @@ pub const Application = extern struct {
|
||||
|
||||
// Setup our GTK init env vars
|
||||
setGtkEnv(&config) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => {
|
||||
error.WriteFailed => {
|
||||
// If we fail to set GTK environment variables then we still
|
||||
// try to start the application...
|
||||
log.warn(
|
||||
@@ -338,7 +344,7 @@ pub const Application = extern struct {
|
||||
// I'm unsure of any scenario where this happens. Because we don't
|
||||
// want to litter null checks everywhere, we just exit here.
|
||||
log.warn("gdk display is null, exiting", .{});
|
||||
std.posix.exit(1);
|
||||
std.process.exit(1);
|
||||
};
|
||||
|
||||
// Setup our windowing protocol logic
|
||||
@@ -1063,7 +1069,11 @@ pub const Application = extern struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn loadCustomCss(self: *Self) (std.fs.File.ReadError || Allocator.Error)!void {
|
||||
const LoadCustomCssError = std.Io.File.OpenError ||
|
||||
compat_file.ReadToEndAllocError ||
|
||||
std.mem.Allocator.Error;
|
||||
|
||||
fn loadCustomCss(self: *Self) LoadCustomCssError!void {
|
||||
const priv: *Private = self.private();
|
||||
const alloc = self.allocator();
|
||||
const display = gdk.Display.getDefault() orelse {
|
||||
@@ -1087,7 +1097,11 @@ pub const Application = extern struct {
|
||||
.optional => |path| .{ path, true },
|
||||
.required => |path| .{ path, false },
|
||||
};
|
||||
const file = std.fs.openFileAbsolute(path, .{}) catch |err| {
|
||||
const file = std.Io.Dir.openFileAbsolute(
|
||||
global.io(),
|
||||
path,
|
||||
.{},
|
||||
) catch |err| {
|
||||
if (err != error.FileNotFound or !optional) {
|
||||
log.warn(
|
||||
"error opening gtk-custom-css file {s}: {}",
|
||||
@@ -1096,12 +1110,14 @@ pub const Application = extern struct {
|
||||
}
|
||||
continue;
|
||||
};
|
||||
defer file.close();
|
||||
defer file.close(global.io());
|
||||
|
||||
const css_file_size_limit = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
log.info("loading gtk-custom-css path={s}", .{path});
|
||||
const contents = file.readToEndAlloc(
|
||||
|
||||
const contents = compat_file.readToEndAlloc(
|
||||
file,
|
||||
alloc,
|
||||
css_file_size_limit,
|
||||
) catch |err| switch (err) {
|
||||
@@ -1111,6 +1127,7 @@ pub const Application = extern struct {
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
defer alloc.free(contents);
|
||||
|
||||
const bytes = glib.Bytes.new(contents.ptr, contents.len);
|
||||
@@ -1401,7 +1418,7 @@ pub const Application = extern struct {
|
||||
const priv = self.private();
|
||||
assert(priv.signal_source == null);
|
||||
priv.signal_source = glib.unixSignalAdd(
|
||||
std.posix.SIG.USR2,
|
||||
@intFromEnum(std.posix.SIG.USR2),
|
||||
handleSigusr2,
|
||||
self,
|
||||
);
|
||||
@@ -1461,7 +1478,7 @@ pub const Application = extern struct {
|
||||
|
||||
// Queue a new window
|
||||
const priv = self.private();
|
||||
_ = priv.core_app.mailbox.push(.{
|
||||
_ = priv.core_app.mailbox.push(global.io(), .{
|
||||
.new_window = .{},
|
||||
}, .{ .forever = {} });
|
||||
|
||||
@@ -1813,7 +1830,7 @@ pub const Application = extern struct {
|
||||
_: ?*glib.Variant,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
_ = self.core().mailbox.push(.open_config, .forever);
|
||||
_ = self.core().mailbox.push(global.io(), .open_config, .forever);
|
||||
}
|
||||
|
||||
fn actionPresentSurface(
|
||||
@@ -1839,6 +1856,7 @@ pub const Application = extern struct {
|
||||
const surface = self.core().findSurfaceByID(surface_id) orelse return;
|
||||
|
||||
_ = self.core().mailbox.push(
|
||||
global.io(),
|
||||
.{
|
||||
.surface_message = .{
|
||||
.surface = surface,
|
||||
@@ -1866,11 +1884,8 @@ pub const Application = extern struct {
|
||||
fn init(class: *Class) callconv(.c) void {
|
||||
// Register our compiled resources exactly once.
|
||||
{
|
||||
const c = @cImport({
|
||||
// generated header files
|
||||
@cInclude("ghostty_resources.h");
|
||||
});
|
||||
if (c.ghostty_get_resource()) |ptr| {
|
||||
const ghostty_gtk_resources = @import("ghostty_gtk_resources");
|
||||
if (ghostty_gtk_resources.ghostty_get_resource()) |ptr| {
|
||||
gio.resourcesRegister(@ptrCast(@alignCast(ptr)));
|
||||
} else {
|
||||
// If we fail to load resources then things will
|
||||
@@ -1894,11 +1909,11 @@ pub const Application = extern struct {
|
||||
};
|
||||
|
||||
pub fn openUrlFallback(self: *Application, kind: apprt.action.OpenUrl.Kind, url: []const u8) void {
|
||||
_ = self;
|
||||
// Fallback to the minimal cross-platform way of opening a URL.
|
||||
// This is always a safe fallback and enables for example Windows
|
||||
// to open URLs (GTK on Windows via WSL is a thing).
|
||||
internal_os.open(
|
||||
self.allocator(),
|
||||
kind,
|
||||
url,
|
||||
) catch |err| log.warn("unable to open url: {}", .{err});
|
||||
@@ -2846,7 +2861,7 @@ const Action = struct {
|
||||
/// given the runtime environment or configuration.
|
||||
///
|
||||
/// This must be called BEFORE GTK initialization.
|
||||
fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void {
|
||||
fn setGtkEnv(config: *const CoreConfig) std.Io.Writer.Error!void {
|
||||
assert(gtk.isInitialized() == 0);
|
||||
|
||||
var gdk_debug: struct {
|
||||
@@ -2863,7 +2878,7 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void {
|
||||
} = .{
|
||||
// `gtk-opengl-debug` dumps logs directly to stderr so both must be true
|
||||
// to enable OpenGL debugging.
|
||||
.opengl = state.logging.stderr and config.@"gtk-opengl-debug",
|
||||
.opengl = global.logging().stderr and config.@"gtk-opengl-debug",
|
||||
};
|
||||
|
||||
var gdk_disable: struct {
|
||||
@@ -2915,8 +2930,7 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void {
|
||||
|
||||
{
|
||||
var buf: [1024]u8 = undefined;
|
||||
var fmt = std.io.fixedBufferStream(&buf);
|
||||
const writer = fmt.writer();
|
||||
var writer: std.Io.Writer = .fixed(&buf);
|
||||
var first: bool = true;
|
||||
inline for (@typeInfo(@TypeOf(gdk_debug)).@"struct".fields) |field| {
|
||||
if (@field(gdk_debug, field.name)) {
|
||||
@@ -2926,15 +2940,14 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void {
|
||||
}
|
||||
}
|
||||
try writer.writeByte(0);
|
||||
const value = fmt.getWritten();
|
||||
const value = writer.buffered();
|
||||
log.warn("setting GDK_DEBUG={s}", .{value[0 .. value.len - 1]});
|
||||
_ = internal_os.setenv("GDK_DEBUG", value[0 .. value.len - 1 :0]);
|
||||
_ = setenv("GDK_DEBUG", @ptrCast(value[0 .. value.len - 1 :0]), 1);
|
||||
}
|
||||
|
||||
{
|
||||
var buf: [1024]u8 = undefined;
|
||||
var fmt = std.io.fixedBufferStream(&buf);
|
||||
const writer = fmt.writer();
|
||||
var writer: std.Io.Writer = .fixed(&buf);
|
||||
var first: bool = true;
|
||||
inline for (@typeInfo(@TypeOf(gdk_disable)).@"struct".fields) |field| {
|
||||
if (@field(gdk_disable, field.name)) {
|
||||
@@ -2944,10 +2957,13 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void {
|
||||
}
|
||||
}
|
||||
try writer.writeByte(0);
|
||||
const value = fmt.getWritten();
|
||||
const value = writer.buffered();
|
||||
log.warn("setting GDK_DISABLE={s}", .{value[0 .. value.len - 1]});
|
||||
_ = internal_os.setenv("GDK_DISABLE", value[0 .. value.len - 1 :0]);
|
||||
_ = setenv("GDK_DISABLE", @ptrCast(value[0 .. value.len - 1 :0]), 1);
|
||||
}
|
||||
|
||||
// Sync environ after altering system env
|
||||
global.syncEnviron();
|
||||
}
|
||||
|
||||
fn findActiveWindow(data: ?*const anyopaque, _: ?*const anyopaque) callconv(.c) c_int {
|
||||
|
||||
@@ -153,7 +153,7 @@ pub const CommandPalette = extern struct {
|
||||
priv.source.removeAll();
|
||||
|
||||
const alloc = Application.default().allocator();
|
||||
var commands: std.ArrayList(*Command) = .{};
|
||||
var commands: std.ArrayList(*Command) = .empty;
|
||||
defer {
|
||||
for (commands.items) |cmd| cmd.unref();
|
||||
commands.deinit(alloc);
|
||||
|
||||
@@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
|
||||
const gio = @import("gio");
|
||||
const glib = @import("glib");
|
||||
const gobject = @import("gobject");
|
||||
const global = @import("../../../global.zig");
|
||||
|
||||
const Binding = @import("../../../input.zig").Binding;
|
||||
const key = @import("../key.zig");
|
||||
@@ -630,6 +631,9 @@ fn generateToken(buf: *Token) [:0]const u8 {
|
||||
return std.fmt.bufPrintZ(
|
||||
buf,
|
||||
"ghostty_{x:0<7}",
|
||||
.{std.crypto.random.int(u28)},
|
||||
.{rand_int: {
|
||||
const rng_impl: std.Random.IoSource = .{ .io = global.io() };
|
||||
break :rand_int rng_impl.interface().int(u28);
|
||||
}},
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ const adw = @import("adw");
|
||||
const gdk = @import("gdk");
|
||||
const gobject = @import("gobject");
|
||||
const gtk = @import("gtk");
|
||||
const global = @import("../../../global.zig");
|
||||
|
||||
const input = @import("../../../input.zig");
|
||||
const gresource = @import("../build/gresource.zig");
|
||||
@@ -61,13 +62,13 @@ pub const ImguiWidget = extern struct {
|
||||
ig_context: ?*cimgui.c.ImGuiContext = null,
|
||||
|
||||
/// Our previous instant used to calculate delta time for animations.
|
||||
instant: ?std.time.Instant = null,
|
||||
instant: ?std.Io.Timestamp = null,
|
||||
|
||||
/// Tick callback ID for timed updates.
|
||||
tick_callback_id: c_uint = 0,
|
||||
|
||||
/// Last render time for throttling to 30 FPS.
|
||||
last_render_time: ?std.time.Instant = null,
|
||||
last_render_time: ?std.Io.Timestamp = null,
|
||||
|
||||
pub var offset: c_int = 0;
|
||||
};
|
||||
@@ -140,10 +141,11 @@ pub const ImguiWidget = extern struct {
|
||||
const priv = self.private();
|
||||
const io: *cimgui.c.ImGuiIO = cimgui.c.ImGui_GetIO();
|
||||
|
||||
const now: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
|
||||
// Determine our delta time
|
||||
const now = std.time.Instant.now() catch unreachable;
|
||||
io.DeltaTime = if (priv.instant) |prev| delta: {
|
||||
const since_ns: f64 = @floatFromInt(now.since(prev));
|
||||
const since_ns: f64 = @floatFromInt(prev.durationTo(now).nanoseconds);
|
||||
const ns_per_s: f64 = @floatFromInt(std.time.ns_per_s);
|
||||
const since_s: f32 = @floatCast(since_ns / ns_per_s);
|
||||
break :delta @max(0.00001, since_s);
|
||||
@@ -298,7 +300,7 @@ pub const ImguiWidget = extern struct {
|
||||
|
||||
// Update last render time for tick callback throttling.
|
||||
const priv = self.private();
|
||||
priv.last_render_time = std.time.Instant.now() catch null;
|
||||
priv.last_render_time = .now(global.io(), .awake);
|
||||
|
||||
// Setup our frame. We render twice because some ImGui behaviors
|
||||
// take multiple renders to process. I don't know how to make this
|
||||
@@ -457,15 +459,10 @@ pub const ImguiWidget = extern struct {
|
||||
const self: *Self = gobject.ext.cast(Self, widget) orelse return 0;
|
||||
const priv = self.private();
|
||||
|
||||
const now = std.time.Instant.now() catch {
|
||||
self.queueRender();
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Throttle to 30 FPS (~33ms between frames)
|
||||
const frame_time_ns: u64 = std.time.ns_per_s / 30;
|
||||
const should_render = if (priv.last_render_time) |last|
|
||||
now.since(last) >= frame_time_ns
|
||||
last.untilNow(global.io(), .awake).nanoseconds >= frame_time_ns
|
||||
else
|
||||
true;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ const Window = @import("window.zig").Window;
|
||||
const InspectorWindow = @import("inspector_window.zig").InspectorWindow;
|
||||
const i18n = @import("../../../os/i18n.zig");
|
||||
const media = @import("../media.zig");
|
||||
const global = @import("../../../global.zig");
|
||||
|
||||
const log = std.log.scoped(.gtk_ghostty_surface);
|
||||
|
||||
@@ -1589,32 +1590,32 @@ pub const Surface = extern struct {
|
||||
return self.private().cursor_pos;
|
||||
}
|
||||
|
||||
pub fn defaultTermioEnv(self: *Self) !std.process.EnvMap {
|
||||
pub fn defaultTermioEnv(self: *Self) !std.process.Environ.Map {
|
||||
const app = Application.default();
|
||||
const alloc = app.allocator();
|
||||
var env = try internal_os.getEnvMap(alloc);
|
||||
var env = try global.environMap();
|
||||
errdefer env.deinit();
|
||||
|
||||
if (app.savedLanguage()) |language| {
|
||||
try env.put("LANG", language);
|
||||
} else {
|
||||
env.remove("LANG");
|
||||
_ = env.orderedRemove("LANG");
|
||||
}
|
||||
|
||||
// Don't leak these GTK environment variables to child processes.
|
||||
env.remove("GDK_DEBUG");
|
||||
env.remove("GDK_DISABLE");
|
||||
env.remove("GSK_RENDERER");
|
||||
_ = env.orderedRemove("GDK_DEBUG");
|
||||
_ = env.orderedRemove("GDK_DISABLE");
|
||||
_ = env.orderedRemove("GSK_RENDERER");
|
||||
|
||||
// Remove some environment variables that are set when Ghostty is launched
|
||||
// from a `.desktop` file, by D-Bus activation, or systemd.
|
||||
env.remove("GIO_LAUNCHED_DESKTOP_FILE");
|
||||
env.remove("GIO_LAUNCHED_DESKTOP_FILE_PID");
|
||||
env.remove("DBUS_STARTER_ADDRESS");
|
||||
env.remove("DBUS_STARTER_BUS_TYPE");
|
||||
env.remove("INVOCATION_ID");
|
||||
env.remove("JOURNAL_STREAM");
|
||||
env.remove("NOTIFY_SOCKET");
|
||||
_ = env.orderedRemove("GIO_LAUNCHED_DESKTOP_FILE");
|
||||
_ = env.orderedRemove("GIO_LAUNCHED_DESKTOP_FILE_PID");
|
||||
_ = env.orderedRemove("DBUS_STARTER_ADDRESS");
|
||||
_ = env.orderedRemove("DBUS_STARTER_BUS_TYPE");
|
||||
_ = env.orderedRemove("INVOCATION_ID");
|
||||
_ = env.orderedRemove("JOURNAL_STREAM");
|
||||
_ = env.orderedRemove("NOTIFY_SOCKET");
|
||||
|
||||
// Unset environment varies set by snaps if we're running in a snap.
|
||||
// This allows Ghostty to further launch additional snaps.
|
||||
@@ -1641,7 +1642,7 @@ pub const Surface = extern struct {
|
||||
}
|
||||
|
||||
/// Filter out environment variables that start with forbidden prefixes.
|
||||
fn filterSnapPaths(gpa: std.mem.Allocator, env_map: *std.process.EnvMap) !void {
|
||||
fn filterSnapPaths(gpa: std.mem.Allocator, env_map: *std.process.Environ.Map) !void {
|
||||
comptime assert(build_config.snap);
|
||||
|
||||
const snap_vars = [_][]const u8{
|
||||
@@ -1708,7 +1709,7 @@ pub const Surface = extern struct {
|
||||
item.key,
|
||||
item.value,
|
||||
);
|
||||
for (env_to_remove.items) |key| _ = env_map.remove(key);
|
||||
for (env_to_remove.items) |key| _ = env_map.orderedRemove(key);
|
||||
}
|
||||
|
||||
pub fn clipboardRequest(
|
||||
|
||||
@@ -176,7 +176,11 @@ test "adding actions to an object" {
|
||||
_ = addAsGroup(gtk.Box, box, "test", &actions);
|
||||
}
|
||||
|
||||
const expected = std.crypto.random.intRangeAtMost(i32, 1, std.math.maxInt(u31));
|
||||
const expected = expected: {
|
||||
const rng_impl: std.Random.IoSource = .{ .io = testing.io };
|
||||
const rng = rng_impl.interface();
|
||||
break :expected rng.intRangeAtMost(i32, 1, std.math.maxInt(u31));
|
||||
};
|
||||
const parameter = glib.Variant.newInt32(expected);
|
||||
|
||||
try testing.expect(box.as(gtk.Widget).activateActionVariant("test.test", parameter) != 0);
|
||||
|
||||
@@ -3,18 +3,16 @@ const std = @import("std");
|
||||
// Until the gobject bindings are built at the same time we are building
|
||||
// Ghostty, we need to import `gtk/gtk.h` directly to ensure that the version
|
||||
// macros match the version of `gtk4` that we are building/linking against.
|
||||
const c = @cImport({
|
||||
@cInclude("gtk/gtk.h");
|
||||
});
|
||||
const gtk_c = @import("gtk_c");
|
||||
|
||||
const gtk = @import("gtk");
|
||||
|
||||
const log = std.log.scoped(.gtk);
|
||||
|
||||
pub const comptime_version: std.SemanticVersion = .{
|
||||
.major = c.GTK_MAJOR_VERSION,
|
||||
.minor = c.GTK_MINOR_VERSION,
|
||||
.patch = c.GTK_MICRO_VERSION,
|
||||
.major = gtk_c.GTK_MAJOR_VERSION,
|
||||
.minor = gtk_c.GTK_MINOR_VERSION,
|
||||
.patch = gtk_c.GTK_MICRO_VERSION,
|
||||
};
|
||||
|
||||
pub fn getRuntimeVersion() std.SemanticVersion {
|
||||
@@ -105,17 +103,17 @@ test "atLeast" {
|
||||
|
||||
const funs = &.{ atLeast, runtimeAtLeast };
|
||||
inline for (funs) |fun| {
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION));
|
||||
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION + 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION + 1, gtk_c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION + 1, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION));
|
||||
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION - 1, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION - 1, gtk_c.GTK_MINOR_VERSION + 1, gtk_c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION - 1, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION + 1));
|
||||
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION - 1, c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION - 1, gtk_c.GTK_MICRO_VERSION + 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,16 +123,16 @@ test "runtimeUntil" {
|
||||
// This is an array in case we add a comptime variant.
|
||||
const funs = &.{runtimeUntil};
|
||||
inline for (funs) |fun| {
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION));
|
||||
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(c.GTK_MAJOR_VERSION + 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION + 1, gtk_c.GTK_MICRO_VERSION));
|
||||
try testing.expect(fun(gtk_c.GTK_MAJOR_VERSION + 1, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION));
|
||||
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION - 1, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION - 1, gtk_c.GTK_MINOR_VERSION + 1, gtk_c.GTK_MICRO_VERSION));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION - 1, gtk_c.GTK_MINOR_VERSION, gtk_c.GTK_MICRO_VERSION + 1));
|
||||
|
||||
try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION - 1, c.GTK_MICRO_VERSION + 1));
|
||||
try testing.expect(!fun(gtk_c.GTK_MAJOR_VERSION, gtk_c.GTK_MINOR_VERSION - 1, gtk_c.GTK_MICRO_VERSION + 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ const Allocator = std.mem.Allocator;
|
||||
|
||||
const gio = @import("gio");
|
||||
const glib = @import("glib");
|
||||
const global = @import("../../../global.zig");
|
||||
|
||||
const apprt = @import("../../../apprt.zig");
|
||||
const ApprtApp = @import("../App.zig");
|
||||
@@ -28,10 +29,12 @@ payload_builder: *glib.VariantBuilder,
|
||||
/// Used to build the parameters for the IPC.
|
||||
parameters_builder: *glib.VariantBuilder,
|
||||
|
||||
pub const InitError = Allocator.Error || std.Io.Writer.Error || apprt.ipc.Errors;
|
||||
|
||||
/// Initialize the helper.
|
||||
pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) (Allocator.Error || std.Io.Writer.Error || apprt.ipc.Errors)!Self {
|
||||
pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) InitError!Self {
|
||||
var buf: [256]u8 = undefined;
|
||||
var stderr_writer = std.fs.File.stderr().writer(&buf);
|
||||
var stderr_writer = std.Io.File.stderr().writer(global.io(), &buf);
|
||||
const stderr = &stderr_writer.interface;
|
||||
|
||||
// Get the appropriate bus name and object path for contacting the
|
||||
@@ -133,7 +136,7 @@ pub fn addParameter(self: *Self, variant: *glib.Variant) void {
|
||||
/// should be done with this object other than call `deinit`.
|
||||
pub fn send(self: *Self) (std.Io.Writer.Error || apprt.ipc.Errors)!void {
|
||||
var buf: [256]u8 = undefined;
|
||||
var stderr_writer = std.fs.File.stderr().writer(&buf);
|
||||
var stderr_writer = std.Io.File.stderr().writer(global.io(), &buf);
|
||||
const stderr = &stderr_writer.interface;
|
||||
|
||||
// finish building the parameters
|
||||
|
||||
@@ -7,10 +7,15 @@ const gio = @import("gio");
|
||||
const glib = @import("glib");
|
||||
const gobject = @import("gobject");
|
||||
const gtk = @import("gtk");
|
||||
const global = @import("../../global.zig");
|
||||
|
||||
pub fn fromFilename(path: [:0]const u8) ?*gtk.MediaFile {
|
||||
assert(std.fs.path.isAbsolute(path));
|
||||
std.fs.accessAbsolute(path, .{ .mode = .read_only }) catch |err| {
|
||||
std.Io.Dir.accessAbsolute(
|
||||
global.io(),
|
||||
path,
|
||||
.{ .read = true },
|
||||
) catch |err| {
|
||||
log.warn("unable to access {s}: {t}", .{ path, err });
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
|
||||
const gio = @import("gio");
|
||||
const global = @import("../../global.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
@@ -11,7 +12,8 @@ const token_format = std.fmt.comptimePrint("{{x:0>{}}}", .{token_hex_len});
|
||||
|
||||
/// Generate a token suitable for use in requests to the XDG Desktop Portal
|
||||
pub fn generateToken() usize {
|
||||
return std.crypto.random.int(usize);
|
||||
const rng_impl: std.Random.IoSource = .{ .io = global.io() };
|
||||
return rng_impl.interface().int(usize);
|
||||
}
|
||||
|
||||
/// Format a request token consistently for use in portal object paths and payloads.
|
||||
|
||||
@@ -9,6 +9,7 @@ const assert = std.debug.assert;
|
||||
const gio = @import("gio");
|
||||
const glib = @import("glib");
|
||||
const gobject = @import("gobject");
|
||||
const global = @import("../../../global.zig");
|
||||
|
||||
const App = @import("../App.zig");
|
||||
const portal = @import("../portal.zig");
|
||||
@@ -23,7 +24,7 @@ app: *App,
|
||||
dbus: ?*gio.DBusConnection = null,
|
||||
|
||||
/// Mutex to protect modification of the entries map or the cleanup timer.
|
||||
mutex: std.Thread.Mutex = .{},
|
||||
mutex: std.Io.Mutex = .init,
|
||||
|
||||
/// Map to store data about any in-flight calls to the portal.
|
||||
entries: std.AutoArrayHashMapUnmanaged(usize, *Entry) = .empty,
|
||||
@@ -78,7 +79,7 @@ const RequestData = struct {
|
||||
/// Data about any in-flight calls to the portal.
|
||||
pub const Entry = struct {
|
||||
/// When the request started.
|
||||
start: std.time.Instant,
|
||||
start: std.Io.Timestamp,
|
||||
/// A token used by the portal to identify requests and responses. The
|
||||
/// actual format of the token does not really matter as long as it can be
|
||||
/// used as part of a D-Bus object path. `usize` was chosen since it's easy
|
||||
@@ -123,8 +124,8 @@ pub fn setDbusConnection(self: *OpenURI, dbus: ?*gio.DBusConnection) void {
|
||||
pub fn deinit(self: *OpenURI) void {
|
||||
const alloc = self.app.app.allocator();
|
||||
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
self.mutex.lockUncancelable(global.io());
|
||||
defer self.mutex.unlock(global.io());
|
||||
|
||||
if (!self.alive) return;
|
||||
self.alive = false;
|
||||
@@ -157,8 +158,8 @@ pub fn start(self: *OpenURI, value: apprt.action.OpenUrl) (Allocator.Error || Er
|
||||
alloc.destroy(request);
|
||||
}
|
||||
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
self.mutex.lockUncancelable(global.io());
|
||||
defer self.mutex.unlock(global.io());
|
||||
|
||||
// Create an entry that is used to track the results of the D-Bus method
|
||||
// call.
|
||||
@@ -166,7 +167,7 @@ pub fn start(self: *OpenURI, value: apprt.action.OpenUrl) (Allocator.Error || Er
|
||||
const entry = try alloc.create(Entry);
|
||||
errdefer alloc.destroy(entry);
|
||||
entry.* = .{
|
||||
.start = std.time.Instant.now() catch return error.TimerUnavailable,
|
||||
.start = std.Io.Timestamp.now(global.io(), .awake),
|
||||
.token = token,
|
||||
.kind = value.kind,
|
||||
.uri = try alloc.dupeZ(u8, value.url),
|
||||
@@ -235,8 +236,8 @@ fn destroyEntry(alloc: Allocator, entry: *Entry) void {
|
||||
}
|
||||
|
||||
fn failRequest(self: *OpenURI, token: usize) ?*Entry {
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
self.mutex.lockUncancelable(global.io());
|
||||
defer self.mutex.unlock(global.io());
|
||||
|
||||
if (!self.alive) return null;
|
||||
|
||||
@@ -422,8 +423,8 @@ fn requestCallback(
|
||||
return;
|
||||
}
|
||||
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
self.mutex.lockUncancelable(global.io());
|
||||
defer self.mutex.unlock(global.io());
|
||||
|
||||
if (!self.alive) return;
|
||||
|
||||
@@ -461,8 +462,8 @@ fn responseReceived(
|
||||
return;
|
||||
};
|
||||
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
self.mutex.lockUncancelable(global.io());
|
||||
defer self.mutex.unlock(global.io());
|
||||
|
||||
if (!self.alive) return;
|
||||
|
||||
@@ -534,22 +535,18 @@ fn cleanup(ud: ?*anyopaque) callconv(.c) c_int {
|
||||
|
||||
const alloc = self.app.app.allocator();
|
||||
|
||||
self.mutex.lock();
|
||||
defer self.mutex.unlock();
|
||||
self.mutex.lockUncancelable(global.io());
|
||||
defer self.mutex.unlock(global.io());
|
||||
|
||||
self.cleanup_timer = null;
|
||||
if (!self.alive) return @intFromBool(glib.SOURCE_REMOVE);
|
||||
|
||||
const now = std.time.Instant.now() catch {
|
||||
// `now()` should never fail, but if it does, don't crash, just return.
|
||||
// This might cause a small memory leak in rare circumstances but it
|
||||
// should get cleaned up the next time a URL is clicked.
|
||||
return @intFromBool(glib.SOURCE_REMOVE);
|
||||
};
|
||||
|
||||
loop: while (true) {
|
||||
for (self.entries.entries.items(.value)) |entry| {
|
||||
if (now.since(entry.start) > cleanup_timeout * std.time.ns_per_s) {
|
||||
if (entry.start.untilNow(
|
||||
global.io(),
|
||||
.awake,
|
||||
).toSeconds() > cleanup_timeout) {
|
||||
log.warn("open uri request timed out token={x}", .{entry.token});
|
||||
self.unsubscribeFromResponse(entry);
|
||||
_ = self.entries.swapRemove(entry.token);
|
||||
|
||||
@@ -2,6 +2,7 @@ const std = @import("std");
|
||||
|
||||
const gio = @import("gio");
|
||||
const glib = @import("glib");
|
||||
const global = @import("../../global.zig");
|
||||
|
||||
const log = std.log.scoped(.gtk_post_fork);
|
||||
|
||||
@@ -85,12 +86,10 @@ pub fn postFork(cmd: *Command) Command.PostForkError!void {
|
||||
return;
|
||||
};
|
||||
|
||||
const start = std.time.Instant.now() catch unreachable;
|
||||
const start: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
|
||||
loop: while (true) {
|
||||
const now = std.time.Instant.now() catch unreachable;
|
||||
|
||||
if (now.since(start) > 250 * std.time.ns_per_ms) {
|
||||
if (start.untilNow(global.io(), .awake).toMilliseconds() > 250) {
|
||||
if (cmd.rt_pre_exec_info.linux_cgroup_hard_fail) {
|
||||
log.err("transition to new transient systemd scope {s} took too long", .{expected_cgroup});
|
||||
return error.PostForkError;
|
||||
@@ -116,6 +115,6 @@ pub fn postFork(cmd: *Command) Command.PostForkError!void {
|
||||
}
|
||||
}
|
||||
|
||||
std.Thread.sleep(25 * std.time.ns_per_ms);
|
||||
std.Io.sleep(global.io(), .fromMilliseconds(25), .awake) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ const std = @import("std");
|
||||
const log = std.log.scoped(.gtk_pre_exec);
|
||||
|
||||
const configpkg = @import("../../config.zig");
|
||||
const global = @import("../../global.zig");
|
||||
|
||||
const internal_os = @import("../../os/main.zig");
|
||||
const Command = @import("../../Command.zig");
|
||||
@@ -47,12 +48,10 @@ pub fn preExec(cmd: *Command) ?u8 {
|
||||
var expected_cgroup_buf: [256]u8 = undefined;
|
||||
const expected_cgroup = cgroup.fmtScope(&expected_cgroup_buf, pid);
|
||||
|
||||
const start = std.time.Instant.now() catch unreachable;
|
||||
const start: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
|
||||
while (true) {
|
||||
const now = std.time.Instant.now() catch unreachable;
|
||||
|
||||
if (now.since(start) > 250 * std.time.ns_per_ms) {
|
||||
if (start.untilNow(global.io(), .awake).toMilliseconds() > 250) {
|
||||
if (cmd.rt_pre_exec_info.linux_cgroup_hard_fail) {
|
||||
log.err("transition to new transient systemd scope took too long", .{});
|
||||
return 127;
|
||||
@@ -74,7 +73,7 @@ pub fn preExec(cmd: *Command) ?u8 {
|
||||
if (std.mem.eql(u8, current_cgroup, expected_cgroup)) return null;
|
||||
}
|
||||
|
||||
std.Thread.sleep(25 * std.time.ns_per_ms);
|
||||
std.Io.sleep(global.io(), .fromMilliseconds(25), .awake) catch unreachable;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -141,7 +141,7 @@ pub const Window = union(Protocol) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addSubprocessEnv(self: *Window, env: *std.process.EnvMap) !void {
|
||||
pub fn addSubprocessEnv(self: *Window, env: *std.process.Environ.Map) !void {
|
||||
switch (self.*) {
|
||||
inline else => |*v| try v.addSubprocessEnv(env),
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ pub const Window = struct {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn addSubprocessEnv(_: *Window, _: *std.process.EnvMap) !void {}
|
||||
pub fn addSubprocessEnv(_: *Window, _: *std.process.Environ.Map) !void {}
|
||||
|
||||
pub fn setUrgent(_: *Window, _: bool) !void {}
|
||||
};
|
||||
|
||||
@@ -225,7 +225,7 @@ pub const Window = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addSubprocessEnv(self: *Window, env: *std.process.EnvMap) !void {
|
||||
pub fn addSubprocessEnv(self: *Window, env: *std.process.Environ.Map) !void {
|
||||
_ = self;
|
||||
_ = env;
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ pub const Window = struct {
|
||||
self.last_applied_decoration_hints = hints;
|
||||
}
|
||||
|
||||
pub fn addSubprocessEnv(self: *Window, env: *std.process.EnvMap) !void {
|
||||
pub fn addSubprocessEnv(self: *Window, env: *std.process.Environ.Map) !void {
|
||||
var buf: [64]u8 = undefined;
|
||||
const window_id = try std.fmt.bufPrint(
|
||||
&buf,
|
||||
|
||||
@@ -126,8 +126,12 @@ pub const Action = union(enum) {
|
||||
/// Sync with: ghostty_ipc_action_u
|
||||
pub const CValue = cvalue: {
|
||||
const key_fields = @typeInfo(Key).@"enum".fields;
|
||||
var union_fields: [key_fields.len]std.builtin.Type.UnionField = undefined;
|
||||
for (key_fields, 0..) |field, i| {
|
||||
|
||||
var names: [key_fields.len][]const u8 = undefined;
|
||||
var types: [key_fields.len]type = undefined;
|
||||
var attrs: [key_fields.len]std.builtin.Type.UnionField.Attributes = undefined;
|
||||
|
||||
for (key_fields, &names, &types, &attrs) |field, *name, *ty, *attr| {
|
||||
const action = @unionInit(Action, field.name, undefined);
|
||||
const Type = t: {
|
||||
const Type = @TypeOf(@field(action, field.name));
|
||||
@@ -135,20 +139,12 @@ pub const Action = union(enum) {
|
||||
if (Type != void and @hasDecl(Type, "C")) break :t Type.C;
|
||||
break :t Type;
|
||||
};
|
||||
|
||||
union_fields[i] = .{
|
||||
.name = field.name,
|
||||
.type = Type,
|
||||
.alignment = @alignOf(Type),
|
||||
};
|
||||
name.* = field.name;
|
||||
ty.* = Type;
|
||||
attr.* = .{ .@"align" = @alignOf(Type) };
|
||||
}
|
||||
|
||||
break :cvalue @Type(.{ .@"union" = .{
|
||||
.layout = .@"extern",
|
||||
.tag_type = null,
|
||||
.fields = &union_fields,
|
||||
.decls = &.{},
|
||||
} });
|
||||
break :cvalue @Union(.@"extern", null, &names, &types, &attrs);
|
||||
};
|
||||
|
||||
/// Sync with: ghostty_ipc_action_s
|
||||
|
||||
@@ -12,6 +12,7 @@ const Allocator = std.mem.Allocator;
|
||||
const terminalpkg = @import("../terminal/main.zig");
|
||||
const Benchmark = @import("Benchmark.zig");
|
||||
const options = @import("options.zig");
|
||||
const global = @import("../global.zig");
|
||||
|
||||
const log = std.log.scoped(.@"apc-parser-bench");
|
||||
|
||||
@@ -19,7 +20,7 @@ opts: Options,
|
||||
stream: Stream,
|
||||
|
||||
/// The file, opened in the setup function.
|
||||
data_f: ?std.fs.File = null,
|
||||
data_f: ?std.Io.File = null,
|
||||
|
||||
pub const Options = struct {
|
||||
/// The data to read as a filepath. If this is "-" then
|
||||
@@ -103,7 +104,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||
fn teardown(ptr: *anyopaque) void {
|
||||
const self: *ApcParser = @ptrCast(@alignCast(ptr));
|
||||
if (self.data_f) |f| {
|
||||
f.close();
|
||||
f.close(global.io());
|
||||
self.data_f = null;
|
||||
}
|
||||
}
|
||||
@@ -114,7 +115,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
|
||||
const f = self.data_f orelse return;
|
||||
|
||||
var read_buf: [64 * 1024]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
const r = &f_reader.interface;
|
||||
|
||||
// This buffer size matches the read buffer size used by the
|
||||
|
||||
@@ -6,6 +6,7 @@ const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const macos = @import("macos");
|
||||
const build_config = @import("../build_config.zig");
|
||||
const global = @import("../global.zig");
|
||||
|
||||
ptr: *anyopaque,
|
||||
vtable: VTable,
|
||||
@@ -64,21 +65,23 @@ pub fn run(
|
||||
signpost.log.release();
|
||||
};
|
||||
|
||||
const start = std.time.Instant.now() catch return error.BenchmarkFailed;
|
||||
const start: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
while (true) {
|
||||
// Run our step function. If it fails, we return the error.
|
||||
try self.vtable.stepFn(self.ptr);
|
||||
result.iterations += 1;
|
||||
|
||||
// Get our current monotonic time and check our exit conditions.
|
||||
const now = std.time.Instant.now() catch return error.BenchmarkFailed;
|
||||
const now: std.Io.Timestamp = .now(global.io(), .awake);
|
||||
const elapsed = start.durationTo(now).nanoseconds;
|
||||
assert(elapsed >= 0);
|
||||
const exit = switch (mode) {
|
||||
.once => true,
|
||||
.duration => |ns| now.since(start) >= ns,
|
||||
.duration => |ns| elapsed >= ns,
|
||||
};
|
||||
|
||||
if (exit) {
|
||||
result.duration = now.since(start);
|
||||
result.duration = @as(u64, @intCast(std.math.clamp(elapsed, 0, std.math.maxInt(u64))));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const cli = @import("cli.zig");
|
||||
const state = &@import("../global.zig").state;
|
||||
const global = @import("../global.zig");
|
||||
|
||||
const log = std.log.scoped(.benchmark);
|
||||
|
||||
@@ -19,7 +19,7 @@ export fn ghostty_benchmark_cli(
|
||||
};
|
||||
|
||||
cli.mainAction(
|
||||
state.alloc,
|
||||
global.alloc(),
|
||||
action,
|
||||
.{ .string = std.mem.sliceTo(args, 0) },
|
||||
) catch |err| {
|
||||
|
||||
@@ -14,13 +14,14 @@ const options = @import("options.zig");
|
||||
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
|
||||
const simd = @import("../simd/main.zig");
|
||||
const table = @import("../unicode/main.zig").table;
|
||||
const global = @import("../global.zig");
|
||||
|
||||
const log = std.log.scoped(.@"terminal-stream-bench");
|
||||
|
||||
opts: Options,
|
||||
|
||||
/// The file, opened in the setup function.
|
||||
data_f: ?std.fs.File = null,
|
||||
data_f: ?std.Io.File = null,
|
||||
|
||||
pub const Options = struct {
|
||||
/// The type of codepoint width calculation to use.
|
||||
@@ -93,7 +94,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||
fn teardown(ptr: *anyopaque) void {
|
||||
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
|
||||
if (self.data_f) |f| {
|
||||
f.close();
|
||||
f.close(global.io());
|
||||
self.data_f = null;
|
||||
}
|
||||
}
|
||||
@@ -114,7 +115,7 @@ fn stepWcwidth(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
var r = &f_reader.interface;
|
||||
|
||||
var d: UTF8Decoder = .{};
|
||||
@@ -141,7 +142,7 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
var r = &f_reader.interface;
|
||||
|
||||
var d: UTF8Decoder = .{};
|
||||
@@ -173,7 +174,7 @@ fn stepSimd(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
var r = &f_reader.interface;
|
||||
|
||||
var d: UTF8Decoder = .{};
|
||||
|
||||
@@ -11,13 +11,14 @@ const options = @import("options.zig");
|
||||
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
|
||||
const unicode = @import("../unicode/main.zig");
|
||||
const uucode = @import("uucode");
|
||||
const global = @import("../global.zig");
|
||||
|
||||
const log = std.log.scoped(.@"terminal-stream-bench");
|
||||
|
||||
opts: Options,
|
||||
|
||||
/// The file, opened in the setup function.
|
||||
data_f: ?std.fs.File = null,
|
||||
data_f: ?std.Io.File = null,
|
||||
|
||||
pub const Options = struct {
|
||||
/// The type of codepoint width calculation to use.
|
||||
@@ -82,7 +83,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||
fn teardown(ptr: *anyopaque) void {
|
||||
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
|
||||
if (self.data_f) |f| {
|
||||
f.close();
|
||||
f.close(global.io());
|
||||
self.data_f = null;
|
||||
}
|
||||
}
|
||||
@@ -92,7 +93,7 @@ fn stepNoop(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
var r = &f_reader.interface;
|
||||
|
||||
var d: UTF8Decoder = .{};
|
||||
@@ -115,7 +116,7 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
var r = &f_reader.interface;
|
||||
|
||||
var d: UTF8Decoder = .{};
|
||||
|
||||
@@ -11,13 +11,14 @@ const options = @import("options.zig");
|
||||
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
|
||||
const uucode = @import("uucode");
|
||||
const symbols_table = @import("../unicode/symbols_table.zig").table;
|
||||
const global = @import("../global.zig");
|
||||
|
||||
const log = std.log.scoped(.@"is-symbol-bench");
|
||||
|
||||
opts: Options,
|
||||
|
||||
/// The file, opened in the setup function.
|
||||
data_f: ?std.fs.File = null,
|
||||
data_f: ?std.Io.File = null,
|
||||
|
||||
pub const Options = struct {
|
||||
/// Which test to run.
|
||||
@@ -80,7 +81,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||
fn teardown(ptr: *anyopaque) void {
|
||||
const self: *IsSymbol = @ptrCast(@alignCast(ptr));
|
||||
if (self.data_f) |f| {
|
||||
f.close();
|
||||
f.close(global.io());
|
||||
self.data_f = null;
|
||||
}
|
||||
}
|
||||
@@ -90,7 +91,7 @@ fn stepUucode(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
var r = &f_reader.interface;
|
||||
|
||||
var d: UTF8Decoder = .{};
|
||||
@@ -117,7 +118,7 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var f_reader = f.reader(&read_buf);
|
||||
var f_reader = f.reader(global.io(), &read_buf);
|
||||
var r = &f_reader.interface;
|
||||
|
||||
var d: UTF8Decoder = .{};
|
||||
|
||||
@@ -9,11 +9,12 @@ const Benchmark = @import("Benchmark.zig");
|
||||
const options = @import("options.zig");
|
||||
const Parser = @import("../terminal/osc.zig").Parser;
|
||||
const log = std.log.scoped(.@"osc-parser-bench");
|
||||
const global = @import("../global.zig");
|
||||
|
||||
opts: Options,
|
||||
|
||||
/// The file, opened in the setup function.
|
||||
data_f: ?std.fs.File = null,
|
||||
data_f: ?std.Io.File = null,
|
||||
|
||||
parser: Parser,
|
||||
|
||||
@@ -70,7 +71,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||
fn teardown(ptr: *anyopaque) void {
|
||||
const self: *OscParser = @ptrCast(@alignCast(ptr));
|
||||
if (self.data_f) |f| {
|
||||
f.close();
|
||||
f.close(global.io());
|
||||
self.data_f = null;
|
||||
}
|
||||
}
|
||||
@@ -80,7 +81,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
|
||||
|
||||
const f = self.data_f orelse return;
|
||||
var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
var r = f.reader(&read_buf);
|
||||
var r = f.reader(global.io(), &read_buf);
|
||||
|
||||
var osc_buf: [4096]u8 align(std.atomic.cache_line) = undefined;
|
||||
while (true) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user