ci: zig fmt check

This adds a CI test to ensure that all Zig files are properly formatted.
This avoids unrelated diff noise in future PRs.
This commit is contained in:
Mitchell Hashimoto
2025-03-18 13:51:39 -07:00
parent c0f5f913c9
commit 4d0bf303c6
10 changed files with 84 additions and 65 deletions

View File

@ -8,7 +8,7 @@ name: Test
jobs: jobs:
required: required:
name: "Required Checks: Test" name: "Required Checks: Test"
runs-on: namespace-profile-ghostty-sm runs-on: namespace-profile-ghostty-xsm
needs: needs:
- build-bench - build-bench
- build-dist - build-dist
@ -31,6 +31,7 @@ jobs:
- translations - translations
- test-pkg-linux - test-pkg-linux
- test-debian-12 - test-debian-12
- zig-fmt
steps: steps:
- id: status - id: status
name: Determine status name: Determine status
@ -612,9 +613,36 @@ jobs:
- name: test - name: test
run: nix develop -c zig build test --system ${{ steps.deps.outputs.deps }} run: nix develop -c zig build test --system ${{ steps.deps.outputs.deps }}
zig-fmt:
if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-xsm
timeout-minutes: 60
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@v4 # Check out repo so we can lint it
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@v1.2.0
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
skipPush: true
useDaemon: false # sometimes fails on short jobs
- name: zig fmt
run: nix develop -c zig fmt --check .
prettier: prettier:
if: github.repository == 'ghostty-org/ghostty' if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-sm runs-on: namespace-profile-ghostty-xsm
timeout-minutes: 60 timeout-minutes: 60
env: env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache ZIG_LOCAL_CACHE_DIR: /zig/local-cache
@ -641,7 +669,7 @@ jobs:
alejandra: alejandra:
if: github.repository == 'ghostty-org/ghostty' if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-sm runs-on: namespace-profile-ghostty-xsm
timeout-minutes: 60 timeout-minutes: 60
env: env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache ZIG_LOCAL_CACHE_DIR: /zig/local-cache
@ -668,7 +696,7 @@ jobs:
typos: typos:
if: github.repository == 'ghostty-org/ghostty' if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-sm runs-on: namespace-profile-ghostty-xsm
timeout-minutes: 60 timeout-minutes: 60
env: env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache ZIG_LOCAL_CACHE_DIR: /zig/local-cache

View File

@ -173,15 +173,6 @@ pub const Binding = struct {
width: c.GLsizei, width: c.GLsizei,
height: c.GLsizei, height: c.GLsizei,
) !void { ) !void {
glad.context.CopyTexSubImage2D.?( glad.context.CopyTexSubImage2D.?(@intFromEnum(b.target), level, xoffset, yoffset, x, y, width, height);
@intFromEnum(b.target),
level,
xoffset,
yoffset,
x,
y,
width,
height
);
} }
}; };

View File

@ -2550,8 +2550,8 @@ fn mouseReport(
.x10 => if (action != .press or .x10 => if (action != .press or
button == null or button == null or
!(button.? == .left or !(button.? == .left or
button.? == .right or button.? == .right or
button.? == .middle)) return, button.? == .middle)) return,
// Doesn't report motion // Doesn't report motion
.normal => if (action == .motion) return, .normal => if (action == .motion) return,
@ -3459,7 +3459,7 @@ pub fn cursorPosCallback(
self.mouse.link_point == null or self.mouse.link_point == null or
(self.mouse.link_point != null and !self.mouse.link_point.?.eql(pos_vp))) and (self.mouse.link_point != null and !self.mouse.link_point.?.eql(pos_vp))) and
(self.io.terminal.flags.mouse_event == .none or (self.io.terminal.flags.mouse_event == .none or
(self.mouse.mods.shift and !self.mouseShiftCapture(false)))) (self.mouse.mods.shift and !self.mouseShiftCapture(false))))
{ {
// If we were previously over a link, we always update. We do this so that if the text // If we were previously over a link, we always update. We do this so that if the text
// changed underneath us, even if the mouse didn't move, we update the URL hints and state // changed underneath us, even if the mouse didn't move, we update the URL hints and state

View File

@ -25,9 +25,9 @@ const oni = @import("oniguruma");
pub const regex = pub const regex =
"(?:" ++ url_schemes ++ "(?:" ++ url_schemes ++
\\)(?: \\)(?:
++ ipv6_url_pattern ++ ++ ipv6_url_pattern ++
\\|[\w\-.~:/?#@!$&*+,;=%]+(?:[\(\[]\w*[\)\]])?)+(?<![,.])|(?:\.\.\/|\.\/*|\/)[\w\-.~:\/?#@!$&*+,;=%]+(?:\/[\w\-.~:\/?#@!$&*+,;=%]*)* \\|[\w\-.~:/?#@!$&*+,;=%]+(?:[\(\[]\w*[\)\]])?)+(?<![,.])|(?:\.\.\/|\.\/*|\/)[\w\-.~:\/?#@!$&*+,;=%]+(?:\/[\w\-.~:\/?#@!$&*+,;=%]*)*
; ;
const url_schemes = const url_schemes =
\\https?://|mailto:|ftp://|file:|ssh:|git://|ssh://|tel:|magnet:|ipfs://|ipns://|gemini://|gopher://|news: \\https?://|mailto:|ftp://|file:|ssh:|git://|ssh://|tel:|magnet:|ipfs://|ipns://|gemini://|gopher://|news:
; ;

View File

@ -139,7 +139,7 @@ pub fn reserve(
const node = self.nodes.items[i]; const node = self.nodes.items[i];
if ((y + height) < best_height or if ((y + height) < best_height or
((y + height) == best_height and ((y + height) == best_height and
(node.width > 0 and node.width < best_width))) (node.width > 0 and node.width < best_width)))
{ {
chosen = i; chosen = i;
best_width = node.width; best_width = node.width;

View File

@ -154,7 +154,7 @@ pub fn calc(face: FaceMetrics) Metrics {
// we place it 1 underline-thickness below the baseline. // we place it 1 underline-thickness below the baseline.
const underline_position = @round(top_to_baseline - const underline_position = @round(top_to_baseline -
(face.underline_position orelse (face.underline_position orelse
-underline_thickness)); -underline_thickness));
// If we don't have a provided strikethrough position // If we don't have a provided strikethrough position
// then we center the strikethrough stroke at half the // then we center the strikethrough stroke at half the
@ -162,7 +162,7 @@ pub fn calc(face: FaceMetrics) Metrics {
// case text. // case text.
const strikethrough_position = @round(top_to_baseline - const strikethrough_position = @round(top_to_baseline -
(face.strikethrough_position orelse (face.strikethrough_position orelse
ex_height * 0.5 + strikethrough_thickness * 0.5)); ex_height * 0.5 + strikethrough_thickness * 0.5));
var result: Metrics = .{ var result: Metrics = .{
.cell_width = @intFromFloat(cell_width), .cell_width = @intFromFloat(cell_width),

View File

@ -2610,29 +2610,29 @@ fn rebuildCells(
// Try to read the cells from the shaping cache if we can. // Try to read the cells from the shaping cache if we can.
self.font_shaper_cache.get(run) orelse self.font_shaper_cache.get(run) orelse
cache: { cache: {
// Otherwise we have to shape them. // Otherwise we have to shape them.
const cells = try self.font_shaper.shape(run); const cells = try self.font_shaper.shape(run);
// Try to cache them. If caching fails for any reason we // Try to cache them. If caching fails for any reason we
// continue because it is just a performance optimization, // continue because it is just a performance optimization,
// not a correctness issue. // not a correctness issue.
self.font_shaper_cache.put( self.font_shaper_cache.put(
self.alloc, self.alloc,
run, run,
cells, cells,
) catch |err| { ) catch |err| {
log.warn( log.warn(
"error caching font shaping results err={}", "error caching font shaping results err={}",
.{err}, .{err},
); );
};
// The cells we get from direct shaping are always owned
// by the shaper and valid until the next shaping call so
// we can safely use them.
break :cache cells;
}; };
// The cells we get from direct shaping are always owned
// by the shaper and valid until the next shaping call so
// we can safely use them.
break :cache cells;
};
// Advance our index until we reach or pass // Advance our index until we reach or pass
// our current x position in the shaper cells. // our current x position in the shaper cells.
while (shaper_cells.?[shaper_cells_i].x < x) { while (shaper_cells.?[shaper_cells_i].x < x) {
@ -2820,29 +2820,29 @@ fn rebuildCells(
// Try to read the cells from the shaping cache if we can. // Try to read the cells from the shaping cache if we can.
self.font_shaper_cache.get(run) orelse self.font_shaper_cache.get(run) orelse
cache: { cache: {
// Otherwise we have to shape them. // Otherwise we have to shape them.
const cells = try self.font_shaper.shape(run); const cells = try self.font_shaper.shape(run);
// Try to cache them. If caching fails for any reason we // Try to cache them. If caching fails for any reason we
// continue because it is just a performance optimization, // continue because it is just a performance optimization,
// not a correctness issue. // not a correctness issue.
self.font_shaper_cache.put( self.font_shaper_cache.put(
self.alloc, self.alloc,
run, run,
cells, cells,
) catch |err| { ) catch |err| {
log.warn( log.warn(
"error caching font shaping results err={}", "error caching font shaping results err={}",
.{err}, .{err},
); );
};
// The cells we get from direct shaping are always owned
// by the shaper and valid until the next shaping call so
// we can safely use them.
break :cache cells;
}; };
// The cells we get from direct shaping are always owned
// by the shaper and valid until the next shaping call so
// we can safely use them.
break :cache cells;
};
const cells = shaper_cells orelse break :glyphs; const cells = shaper_cells orelse break :glyphs;
// If there are no shaper cells for this run, ignore it. // If there are no shaper cells for this run, ignore it.

View File

@ -212,7 +212,7 @@ pub const LoadingImage = struct {
if (std.mem.startsWith(u8, path, "/proc/") or if (std.mem.startsWith(u8, path, "/proc/") or
std.mem.startsWith(u8, path, "/sys/") or std.mem.startsWith(u8, path, "/sys/") or
(std.mem.startsWith(u8, path, "/dev/") and (std.mem.startsWith(u8, path, "/dev/") and
!std.mem.startsWith(u8, path, "/dev/shm/"))) !std.mem.startsWith(u8, path, "/dev/shm/")))
{ {
return error.InvalidData; return error.InvalidData;
} }

View File

@ -621,7 +621,7 @@ pub fn RefCountedSet(
// to minimize the time it takes to find it. // to minimize the time it takes to find it.
if (item.meta.psl < held_item.meta.psl or if (item.meta.psl < held_item.meta.psl or
item.meta.psl == held_item.meta.psl and item.meta.psl == held_item.meta.psl and
item.meta.ref < held_item.meta.ref) item.meta.ref < held_item.meta.ref)
{ {
// Put our held item in the bucket. // Put our held item in the bucket.
table[p] = held_id; table[p] = held_id;

View File

@ -1322,7 +1322,7 @@ pub fn Stream(comptime Handler: type) type {
input.params.len == 3) and input.params.len == 3) and
// we only support window title // we only support window title
(input.params[1] == 0 or (input.params[1] == 0 or
input.params[1] == 2)) input.params[1] == 2))
{ {
// push/pop title // push/pop title
if (@hasDecl(T, "pushPopTitle")) { if (@hasDecl(T, "pushPopTitle")) {