mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-31 04:39:01 +00:00
Update to Zig 0.16.0 (#12726)
Closes #12228 Supersedes #12388 **UPDATED** - Also check comments for additional details! This commit represents the majority of the work necessary to upgrade Ghostty to use Zig 0.16.0. At this point, all tests pass under Linux, but more work may be necessary to get them to build and function on other platforms. There are some parts of this update that deserve commentary, so that follows below: ## Expanded use of global state (IO/environment related) Global state, once generally only used by the C library, has now been expanded to be used across the project at large. The static local variable that holds the state has been moved private in its source container with all attributes that need to be accessed globally gated behind accessors, most of which guard on testing and send test copies instead. Use of the global state in non-testing scenarios asserts that the state has been initialized through `init` naturally through the optional assertion process. The rationale for this change is to have a location to store a general-purpose I/O implementation and environment variables, both of which are now provided through [Juicy Main](https://ziglang.org/download/0.16.0/release-notes.html#Juicy-Main) and hence can no longer be accessed or mutated through stdlib without use of lower-level system calls and hacks (some of which are employed, but sparingly). As the code matures, dependence on global state should naturally slim down. We do not allow global state to be used in libghostty-vt. There are comptime guards that prevent this should compilation of libghostty-vt end up pulling `global.zig`. This means that as per the last paragraph, work has already begun to de-couple the codebase from global state where necessary. Additionally, in some places where environment needs to be updated and where it can be done in an isolated fashion, environment maps are used - system-level injection of environment through the use of `setenv` or `unsetenv` now only happens during early initialization (and hopefully we can remove these in the future too, especially since they require re-synchronization of the higher-level environment primitives after this is done). ## The `lib/compat` Tree Some stdlib features that have been removed but still either seem they would be valuable to us or outright complex to move away from (particularly `SegmentedList`) have been extracted from 0.15.2, updated as needed, and placed in `src/lib/compat`. The intention again is to allow for piecemeal migration to more modern implementations or possibly straight local versions. This paradigm has also allowed us to add `std.Io.Condition.waitTimeout`, which incidentally was missed in the 0.16.0 shuffle and has been re-added for 0.17.0. We can remove this in favor of the upstream when we eventually migrate to that, obviously. Note that there was a lot more of this extracted code when this work was started, but a lot of said code has been removed (namely environment or process/fd-related functionality). ## translate-c Issues (functional on Linux, Darwin WIP) There have been a number of C translation issues that we have been working through through submitted patches and the great help from folks on the Arocc and Zig side. This is ongoing, with the remaining work to getting things fixed mainly focused on the MacOS side. Stay tuned for further developments. As mentioned at the top, follow comments for more details!
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
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,10 +11,11 @@ zig-cache/
|
||||
.zig-cache/
|
||||
zig-pkg/
|
||||
zig-out/
|
||||
zig-pkg/
|
||||
build-cmake/
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
/build.zig.zon.bak
|
||||
build.zig.zon.bak
|
||||
/result*
|
||||
/.nixos-test-history
|
||||
example/*.wasm
|
||||
@@ -30,3 +31,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://deps.files.ghostty.org/translate_c-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://deps.files.ghostty.org/libxev-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://deps.files.ghostty.org/vaxis-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://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.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://deps.files.ghostty.org/zig_objc-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://deps.files.ghostty.org/zig_js-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://deps.files.ghostty.org/uucode-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://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.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://deps.files.ghostty.org/zf-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://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst",
|
||||
.hash = "gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
@@ -90,7 +99,7 @@
|
||||
.lazy = true,
|
||||
},
|
||||
.wayland_protocols = .{
|
||||
.url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz",
|
||||
.hash = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
90
build.zig.zon.json
generated
90
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://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst",
|
||||
"hash": "sha256-cZGf9a1+sDeORKWYIdzQ/5KLT7l/9pgPc2cIbqfBc4o="
|
||||
},
|
||||
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
|
||||
"name": "gtk4_layer_shell",
|
||||
@@ -51,7 +56,7 @@
|
||||
},
|
||||
"N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI": {
|
||||
"name": "imgui",
|
||||
"url": "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz",
|
||||
"hash": "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs="
|
||||
},
|
||||
"N-V-__8AALZGBAAS5NLVH-c8eC-6VtCdcH-9nUvVfUSkWS__": {
|
||||
@@ -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://deps.files.ghostty.org/libxev-9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz",
|
||||
"hash": "sha256-fOU1oxIxfoEgoLuWz7fVX6M+zmqpo7gqZObWiH/aDE0="
|
||||
},
|
||||
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
|
||||
"name": "libxml2",
|
||||
@@ -109,70 +114,75 @@
|
||||
"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://deps.files.ghostty.org/translate_c-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://deps.files.ghostty.org/uucode-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://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"hash": "sha256-z3J3w+oYapfAZZR+MvWXwg+th1hePDA1TptnKFO4r+M="
|
||||
},
|
||||
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
|
||||
"name": "wayland",
|
||||
"url": "https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz",
|
||||
"hash": "sha256-6kGR1o5DdnflHzqs3ieCmBAUTpMdOXoyfcYDXiw5xQ0="
|
||||
},
|
||||
"N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA": {
|
||||
"name": "wayland_protocols",
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz",
|
||||
"hash": "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM="
|
||||
},
|
||||
"N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S": {
|
||||
"name": "wayland_protocols",
|
||||
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
"hash": "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg="
|
||||
},
|
||||
"N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA": {
|
||||
"name": "wayland_protocols",
|
||||
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
"hash": "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM="
|
||||
},
|
||||
"N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs": {
|
||||
"name": "wuffs",
|
||||
"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://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.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://deps.files.ghostty.org/zf-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://deps.files.ghostty.org/zig_js-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://deps.files.ghostty.org/zig_objc-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://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.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",
|
||||
|
||||
120
build.zig.zon.nix
generated
120
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://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst";
|
||||
hash = "sha256-cZGf9a1+sDeORKWYIdzQ/5KLT7l/9pgPc2cIbqfBc4o=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
@@ -187,7 +200,7 @@ in
|
||||
name = "N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI";
|
||||
path = fetchZigArtifact {
|
||||
name = "imgui";
|
||||
url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz";
|
||||
url = "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz";
|
||||
hash = "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs=";
|
||||
unpack = false;
|
||||
};
|
||||
@@ -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://deps.files.ghostty.org/libxev-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://deps.files.ghostty.org/translate_c-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://deps.files.ghostty.org/uucode-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://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz";
|
||||
hash = "sha256-z3J3w+oYapfAZZR+MvWXwg+th1hePDA1TptnKFO4r+M=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
@@ -327,6 +349,15 @@ in
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA";
|
||||
path = fetchZigArtifact {
|
||||
name = "wayland_protocols";
|
||||
url = "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz";
|
||||
hash = "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S";
|
||||
path = fetchZigArtifact {
|
||||
@@ -336,15 +367,6 @@ in
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA";
|
||||
path = fetchZigArtifact {
|
||||
name = "wayland_protocols";
|
||||
url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz";
|
||||
hash = "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs";
|
||||
path = fetchZigArtifact {
|
||||
@@ -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://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.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://deps.files.ghostty.org/zf-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://deps.files.ghostty.org/zig_js-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://deps.files.ghostty.org/zig_objc-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://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.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;
|
||||
};
|
||||
}
|
||||
|
||||
28
build.zig.zon.txt
generated
28
build.zig.zon.txt
generated
@@ -1,6 +1,9 @@
|
||||
git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732
|
||||
git+https://github.com/rockorager/libvaxis.git#c1e1f23be38951c425cdf31af455ba23ef178940
|
||||
git+https://github.com/zigimg/zigimg#d695acd97c02e57bb151e8f659d1280f5cd6ca70
|
||||
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/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz
|
||||
https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz
|
||||
https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz
|
||||
https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz
|
||||
https://deps.files.ghostty.org/fontconfig-2.14.2.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/gobject-2026-04-23-26-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/libxev-9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.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/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz
|
||||
https://deps.files.ghostty.org/uucode-2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz
|
||||
https://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz
|
||||
https://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.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/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.tar.gz
|
||||
https://deps.files.ghostty.org/zf-c35c421f84895193246db06c40683c1a30e616ef.tar.gz
|
||||
https://deps.files.ghostty.org/zig_js-3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz
|
||||
https://deps.files.ghostty.org/zig_objc-c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz
|
||||
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
|
||||
https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
|
||||
https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz
|
||||
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz
|
||||
https://github.com/vancluever/arocc/archive/ecbc5c799574e0da2758a961b12efa586007f03c.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://deps.files.ghostty.org/gobject-2026-04-23-26-1.tar.zst",
|
||||
"dest": "vendor/p/gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp",
|
||||
"sha256": "642e324b3644c00464a2161e4af497f73cbbe8ce02a4c0edb92aacb365748047"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
@@ -61,7 +67,7 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI",
|
||||
"sha256": "c816c20e8c75f3e15ae867350e79925502d1a6a85938bb1a73b8927e5f31f9cb"
|
||||
},
|
||||
@@ -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://deps.files.ghostty.org/libxev-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://deps.files.ghostty.org/translate_c-a916baf225a3cfc93a982225462db612604ae290.tar.gz",
|
||||
"dest": "vendor/p/translate_c-0.0.0-Q_BUWj8_BwCr4na219OimiKKj4IVSq0aKtMXCQmIk4AB",
|
||||
"sha256": "4fd2a2b21dbc49c22bea6854a59a7568dc77183760531ace3cf8da1267696afd"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/uucode-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://deps.files.ghostty.org/vaxis-1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz",
|
||||
"dest": "vendor/p/vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka",
|
||||
"sha256": "3ea050e905887c46bca1a2c18e41d6edf574c1aa6ebfbc5cf3c52846275e4fa8"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
@@ -157,15 +169,15 @@
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
|
||||
"sha256": "5cedcadde81b75e60f23e5e83b5dd2b8eb4efb9f8f79bd7a347d148aeb0530f8"
|
||||
"url": "https://deps.files.ghostty.org/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
"sha256": "dd2df14ab5f41038257aaedcc4b5fb9ac0ee018f3f0f94af9097028e60d33223"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
"sha256": "dd2df14ab5f41038257aaedcc4b5fb9ac0ee018f3f0f94af9097028e60d33223"
|
||||
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
|
||||
"sha256": "5cedcadde81b75e60f23e5e83b5dd2b8eb4efb9f8f79bd7a347d148aeb0530f8"
|
||||
},
|
||||
{
|
||||
"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://deps.files.ghostty.org/z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR.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://deps.files.ghostty.org/zf-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://deps.files.ghostty.org/zig_js-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://deps.files.ghostty.org/zig_objc-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://deps.files.ghostty.org/wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX.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",
|
||||
|
||||
@@ -785,12 +785,13 @@ typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_MEDIUM_FILE = 16,
|
||||
|
||||
/**
|
||||
* Enable or disable Kitty image loading via the temporary file medium.
|
||||
* Enable Kitty image loading via the temporary file medium, restricted to
|
||||
* the provided directory. The string data is copied into the terminal.
|
||||
*
|
||||
* A NULL value pointer is a no-op. Has no effect when Kitty graphics
|
||||
* are disabled at build time.
|
||||
* A NULL value pointer disables the temporary file medium. Has no effect
|
||||
* when Kitty graphics are disabled at build time.
|
||||
*
|
||||
* Input type: bool*
|
||||
* Input type: GhosttyString*
|
||||
*/
|
||||
GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_MEDIUM_TEMP_FILE = 17,
|
||||
|
||||
@@ -1139,12 +1140,13 @@ typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_MEDIUM_FILE = 27,
|
||||
|
||||
/**
|
||||
* Whether the temporary file medium is enabled for Kitty image loading
|
||||
* on the active screen.
|
||||
* The directory allowed for Kitty image loading via the temporary file
|
||||
* medium on the active screen. The string is empty when the medium is
|
||||
* disabled.
|
||||
*
|
||||
* Returns GHOSTTY_NO_VALUE when Kitty graphics are disabled at build time.
|
||||
*
|
||||
* Output type: bool *
|
||||
* Output type: GhosttyString *
|
||||
*/
|
||||
GHOSTTY_TERMINAL_DATA_KITTY_IMAGE_MEDIUM_TEMP_FILE = 28,
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -2,23 +2,34 @@
|
||||
|
||||
# This script downloads external dependencies from build.zig.zon.json that
|
||||
# are not already mirrored at deps.files.ghostty.org, saves them to a local
|
||||
# directory, and updates build.zig.zon to point to the new mirror URLs.
|
||||
# directory, and updates the build.zig.zon files (the root one as well as
|
||||
# every pkg/*/build.zig.zon) to point to the new mirror URLs.
|
||||
#
|
||||
# The downloaded files are unmodified so their checksums and content hashes
|
||||
# will match the originals.
|
||||
#
|
||||
# After running this script, the files in the output directory can be uploaded
|
||||
# to blob storage, and build.zig.zon will already be updated with the new URLs.
|
||||
# to blob storage, and the build.zig.zon files will already be updated with
|
||||
# the new URLs.
|
||||
def main [
|
||||
--output: string = "tmp-mirror", # Output directory for the mirrored files
|
||||
--prefix: string = "https://deps.files.ghostty.org/", # Final URL prefix to ignore
|
||||
--dry-run, # Print what would be downloaded without downloading
|
||||
] {
|
||||
let script_dir = ($env.CURRENT_FILE | path dirname)
|
||||
let input_file = ($script_dir | path join ".." ".." "build.zig.zon.json")
|
||||
let zon_file = ($script_dir | path join ".." ".." "build.zig.zon")
|
||||
let root_dir = ($script_dir | path join ".." ".." | path expand)
|
||||
let input_file = ($root_dir | path join "build.zig.zon.json")
|
||||
let output_dir = $output
|
||||
|
||||
# All build.zig.zon files that may reference external URLs: the root
|
||||
# one plus every package under pkg/. build.zig.zon.json is generated
|
||||
# from the full dependency tree so it covers all of these.
|
||||
let zon_files = (
|
||||
[($root_dir | path join "build.zig.zon")]
|
||||
| append (glob ($root_dir | path join "pkg" "*" "build.zig.zon"))
|
||||
| sort
|
||||
)
|
||||
|
||||
# Ensure the output directory exists
|
||||
mkdir $output_dir
|
||||
|
||||
@@ -75,22 +86,34 @@ def main [
|
||||
|
||||
if $dry_run {
|
||||
print "Dry run complete - no files were downloaded\n"
|
||||
print $"Would update ($url_replacements | length) URLs in build.zig.zon"
|
||||
} else {
|
||||
print "All dependencies downloaded successfully\n"
|
||||
print $"Updating ($zon_file)..."
|
||||
|
||||
# Backup the old file
|
||||
let backup_file = $"($zon_file).bak"
|
||||
cp $zon_file $backup_file
|
||||
print $"Backed up to ($backup_file)"
|
||||
|
||||
mut zon_content = (open $zon_file)
|
||||
for replacement in $url_replacements {
|
||||
$zon_content = ($zon_content | str replace $replacement.old $replacement.new)
|
||||
}
|
||||
$zon_content | save -f $zon_file
|
||||
}
|
||||
|
||||
print $"Updated ($url_replacements | length) URLs in build.zig.zon"
|
||||
# Apply the URL replacements to every build.zig.zon that references them.
|
||||
for zon_file in $zon_files {
|
||||
mut zon_content = (open --raw $zon_file)
|
||||
mut count = 0
|
||||
for replacement in $url_replacements {
|
||||
if ($zon_content | str contains $replacement.old) {
|
||||
$zon_content = ($zon_content | str replace --all $replacement.old $replacement.new)
|
||||
$count = $count + 1
|
||||
}
|
||||
}
|
||||
|
||||
if $count == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
let relative_path = ($zon_file | path relative-to $root_dir)
|
||||
if $dry_run {
|
||||
print $"Would update ($count) URLs in ($relative_path)"
|
||||
} else {
|
||||
# Backup the old file
|
||||
let backup_file = $"($zon_file).bak"
|
||||
cp $zon_file $backup_file
|
||||
$zon_content | save -f $zon_file
|
||||
print $"Updated ($count) URLs in ($relative_path), backup at ($relative_path).bak"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
.imgui = .{
|
||||
// https://github.com/ocornut/imgui
|
||||
.url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
|
||||
.url = "https://deps.files.ghostty.org/N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI.tar.gz",
|
||||
.hash = "N-V-__8AAEbOfQBnvcFcCX2W5z7tDaN8vaNZGamEQtNOe0UI",
|
||||
.lazy = true,
|
||||
},
|
||||
|
||||
@@ -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://deps.files.ghostty.org/translate_c-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://deps.files.ghostty.org/translate_c-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://deps.files.ghostty.org/translate_c-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://deps.files.ghostty.org/translate_c-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();
|
||||
|
||||
307
src/Command.zig
307
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 = try 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 = .NOENT;
|
||||
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) break :execve .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 {};
|
||||
@@ -257,6 +291,17 @@ fn startPosix(self: *Command, arena: Allocator) !void {
|
||||
return error.ExecFailedInChild;
|
||||
}
|
||||
|
||||
/// Wrapper for the raw fork syscall. This preserves the error handling from
|
||||
/// the std.posix wrapper that was removed in Zig 0.16.
|
||||
fn fork() !posix.pid_t {
|
||||
const rc = posix.system.fork();
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.AGAIN, .NOMEM => return error.SystemResources,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn startWindows(self: *Command, arena: Allocator) !void {
|
||||
const cwd_w = if (self.cwd) |cwd| try std.unicode.utf8ToUtf16LeAllocZ(arena, cwd) else null;
|
||||
|
||||
@@ -275,15 +320,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 +371,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 +391,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 +415,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 +430,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 +455,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 +487,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: u32 = if (block) wait_block: {
|
||||
var status: if (builtin.link_libc) c_int else u32 = undefined;
|
||||
_ = try waitPid(self.pid.?, &status, 0);
|
||||
break :wait_block @bitCast(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 +518,32 @@ 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: if (builtin.link_libc) c_int else u32 = undefined;
|
||||
const pid = try waitPid(self.pid.?, &status, posix.system.W.NOHANG);
|
||||
if (pid != 0) break :wait_nohang @bitCast(status);
|
||||
}
|
||||
};
|
||||
|
||||
return .init(res.status);
|
||||
return .init(status);
|
||||
}
|
||||
|
||||
/// Wrapper for the raw waitpid syscall. Status is only initialized on success;
|
||||
/// interrupted waits are retried and all other errors are propagated.
|
||||
fn waitPid(
|
||||
pid: posix.pid_t,
|
||||
status: *if (builtin.link_libc) c_int else u32,
|
||||
flags: u32,
|
||||
) !posix.pid_t {
|
||||
while (true) {
|
||||
const rc = posix.system.waitpid(pid, status, @intCast(flags));
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.INTR => continue,
|
||||
.CHILD => return error.NoChildProcess,
|
||||
.INVAL => return error.InvalidWaitOptions,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets command->data to data.
|
||||
@@ -587,7 +691,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 +742,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 +801,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 +834,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 +864,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 +878,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 +914,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 +933,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 +965,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 +995,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 +1027,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,35 @@ 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 = if (internal_os.isFlatpak())
|
||||
std.process.Environ.Map.init(alloc)
|
||||
else
|
||||
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 +1645,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 +1712,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 = .{};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user