Rewrite the formatter in Zig, dropping the partial python dependency.

Also added a check for .zon but not .zig.zon which is the preferred extension.
This commit is contained in:
IntegratedQuantum 2025-01-24 21:04:03 +01:00
parent 2b3f56a33c
commit d8723da57c
4 changed files with 123 additions and 57 deletions

View File

@ -1,6 +1,6 @@
# This is a basic workflow that is manually triggered
name: CI
name: Compilation and Format Check
on:
push:
@ -20,15 +20,4 @@ jobs:
- run: sudo apt install libgl-dev libasound2-dev libx11-dev
- run: zig build
- run: zig build -Dtarget=x86_64-windows-gnu
format_check:
runs-on: ubuntu-latest
name: Format Check
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- run: python3 "format_check.py"
- run: zig build format --summary none

View File

@ -112,4 +112,24 @@ pub fn build(b: *std.Build) !void {
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_exe_tests.step);
// MARK: Formatter
const formatter = b.addExecutable(.{
.name = "CubyzigFormatter",
.root_source_file = b.path("src/formatter/format.zig"),
.target = target,
.optimize = optimize,
});
const formatter_install = b.addInstallArtifact(formatter, .{});
const formatter_cmd = b.addRunArtifact(formatter);
formatter_cmd.step.dependOn(&formatter_install.step);
if (b.args) |args| {
formatter_cmd.addArgs(args);
}
const formatter_step = b.step("format", "Check the formatting of the code");
formatter_step.dependOn(&formatter_cmd.step);
}

View File

@ -1,44 +0,0 @@
import os
import sys
directory = os.fsencode(".")
fails = 0
for subdir, dirs, files in os.walk("."):
for file in files:
#print os.path.join(subdir, file)
filepath = subdir + os.sep + file
if filepath.startswith(f".{os.sep}compiler"): continue
if filepath.startswith(f".{os.sep}saves"): continue
if filepath.startswith(f".{os.sep}serverAssets"): continue
if filepath.startswith(f".{os.sep}zig-cache"): continue
if filepath.startswith(f".{os.sep}.zig-cache"): continue
if filepath.endswith(".json") or filepath.endswith(".zig") or filepath.endswith(".py") or filepath.endswith(".zon") or filepath.endswith(".vs") or filepath.endswith(".fs") or filepath.endswith(".glsl"):
with open(filepath, "r", newline = '', encoding="utf-8") as f:
string = f.read()
line = 1
lineStart = True
for i, c in enumerate(string):
if(c == '\r'):
print("Incorrect line ending \\r in file ", filepath, " in line ", line, ". Please configure your editor to use LF instead of CRLF.")
fails += 1
elif(c == '\n'):
line += 1
lineStart = True
elif(c == ' '):
if(lineStart):
print("Incorrect indentation in file ", filepath, " in line ", line, ". Please use tabs instead of spaces.")
fails += 1
lineStart = False # avoid repeating this error multiple times
elif(c == '\t'):
continue
elif(lineStart):
lineStart = False
else:
continue
if(fails != 0):
sys.exit(1)
sys.exit(0)

101
src/formatter/format.zig Normal file
View File

@ -0,0 +1,101 @@
const std = @import("std");
var global_gpa = std.heap.GeneralPurposeAllocator(.{.thread_safe=true}){};
pub const globalAllocator = global_gpa.allocator();
var failed: bool = false;
fn printError(msg: []const u8, filePath: []const u8, data: []const u8, charIndex: usize) void {
var lineStart: usize = 0;
var lineNumber: usize = 1;
var lineEnd: usize = 0;
for(data[0..charIndex], 0..) |c, i| {
if(c == '\n') {
lineStart = i + 1;
lineNumber += 1;
}
}
for(data[charIndex..], charIndex..) |c, i| {
if(c == '\n') {
lineEnd = i;
break;
}
}
var startLineChars = std.ArrayList(u8).init(globalAllocator);
defer startLineChars.deinit();
for(data[lineStart..charIndex]) |c| {
if(c == '\t') {
startLineChars.append('\t') catch {};
} else {
startLineChars.append(' ') catch {};
}
}
failed = true;
std.log.err("Found formatting error in line {} of file {s}: {s}\n{s}\n{s}^", .{lineNumber, filePath, msg, data[lineStart..lineEnd], startLineChars.items});
}
fn checkFile(dir: std.fs.Dir, filePath: []const u8) !void {
const data = try dir.readFileAlloc(globalAllocator, filePath, std.math.maxInt(usize));
defer globalAllocator.free(data);
var lineStart: bool = true;
for(data, 0..) |c, i| {
switch(c) {
'\n' => {
lineStart = true;
},
'\r' => {
printError("Incorrect line ending \\r. Please configure your editor to use LF instead CRLF.", filePath, data, i);
},
' ' => {
if(lineStart) {
printError("Incorrect indentation. Please use tabs instead of spaces.", filePath, data, i);
}
},
'\t' => {},
else => {
lineStart = false;
}
}
}
}
fn checkDirectory(dir: std.fs.Dir) !void {
var walker = try dir.walk(globalAllocator);
defer walker.deinit();
while(try walker.next()) |child| {
if(std.mem.endsWith(u8, child.basename, ".zon") and !std.mem.endsWith(u8, child.basename, ".zig.zon")) {
std.log.err("File name should end with .zig.zon so it gets syntax highlighting on github.", .{});
failed = true;
}
if(child.kind == .file and (
std.mem.endsWith(u8, child.basename, ".zig")
or std.mem.endsWith(u8, child.basename, ".zon")
or std.mem.endsWith(u8, child.basename, ".vs")
or std.mem.endsWith(u8, child.basename, ".fs")
or std.mem.endsWith(u8, child.basename, ".glsl")
)) {
try checkFile(dir, child.path);
}
}
}
pub fn main() !void {
defer _ = global_gpa.deinit();
var dir = try std.fs.cwd().openDir("src", .{.iterate = true});
defer dir.close();
try checkDirectory(dir);
dir.close();
dir = try std.fs.cwd().openDir("assets", .{.iterate = true});
try checkDirectory(dir);
try checkFile(std.fs.cwd(), "build.zig");
try checkFile(std.fs.cwd(), "build.zig.zon");
if(failed) std.posix.exit(1);
}