Skip to content

Commit

Permalink
Merge branch 'main' into lsp-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nolanderc authored Oct 26, 2023
2 parents 39218db + 3de894f commit 687922c
Show file tree
Hide file tree
Showing 10 changed files with 978 additions and 466 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "Pull Request CI"
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: write
jobs:
build-pull-request:
strategy:
matrix:
target:
- "x86_64-linux-musl"
- "aarch64-linux-musl"
- "x86_64-macos"
- "aarch64-macos"
- "x86_64-windows"
- "aarch64-windows"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Zig
uses: goto-bus-stop/[email protected]
with:
version: 0.12.0-dev.790+ad6f8e3a5
- name: Build
run: zig build -Dtarget=${{ matrix.target }}
test-pull-request:
strategy:
matrix:
os:
- "ubuntu-latest"
- "windows-latest"
- "macos-latest"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Setup Zig
uses: goto-bus-stop/[email protected]
with:
version: 0.12.0-dev.790+ad6f8e3a5
- name: Test
run: zig build test

99 changes: 71 additions & 28 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,83 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const exe = b.addExecutable(.{
.name = "glsl_analyzer",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
try attachModules(exe);
b.installArtifact(exe);
// Executable
{
const exe = try addExecutable(b, .{ .target = target, .optimize = optimize });
b.installArtifact(exe);

const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());

if (b.args) |args| {
run_cmd.addArgs(args);
}
if (b.args) |args| {
run_cmd.addArgs(args);
}

const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

const unit_tests = b.addTest(.{
.name = "unit-tests",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
try attachModules(unit_tests);
// Tests
{
const unit_tests = b.addTest(.{
.name = "unit-tests",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
try attachModules(unit_tests);

if (b.option(bool, "install-tests", "Install the unit tests in the `bin` folder") orelse false) {
b.installArtifact(unit_tests);
}

const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}

if (b.option(bool, "install-tests", "Install the unit tests in the `bin` folder") orelse false) {
b.installArtifact(unit_tests);
// Release
{
const target_triples = [_][]const u8{
"x86_64-linux-musl",
"aarch64-linux-musl",
"x86_64-macos",
"aarch64-macos",
"x86_64-windows",
"aarch64-windows",
};
const release_step = b.step("release", "Produce executables for targeted platforms");

for (&target_triples) |triple| {
const release_target = try std.zig.CrossTarget.parse(.{
.arch_os_abi = triple,
.cpu_features = "baseline",
});

const exe = try addExecutable(b, .{ .target = release_target, .optimize = optimize });
const install = b.addInstallArtifact(exe, .{
.dest_dir = .{ .override = .{
.custom = b.pathJoin(&.{ triple, "bin" }),
} },
});

release_step.dependOn(&install.step);
}
}
}

const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
fn addExecutable(b: *std.Build, options: struct {
target: std.zig.CrossTarget,
optimize: std.builtin.OptimizeMode,
}) !*std.Build.CompileStep {
const exe = b.addExecutable(.{
.name = "glsl_analyzer",
.root_source_file = .{ .path = "src/main.zig" },
.target = options.target,
.optimize = options.optimize,
});
try attachModules(exe);
return exe;
}

fn attachModules(step: *std.Build.CompileStep) !void {
Expand All @@ -54,7 +97,7 @@ fn attachModules(step: *std.Build.CompileStep) !void {
&.{b.build_root.path orelse "."},
);
options.addOption([]const u8, "build_root", build_root_path);
options.addOption([]const u8, "version", b.exec(&.{ "git", "describe", "--tags" }));
options.addOption([]const u8, "version", b.exec(&.{ "git", "describe", "--tags", "--always" }));
step.addOptions("build_options", options);
}

Expand Down
4 changes: 3 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ watch *ARGS:

test:
zig build test --summary failures {{flags}}
just install
tests/run-all-tests.sh

test-file *ARGS:
zig test {{flags}} "$@"
Expand All @@ -39,4 +41,4 @@ generate-spec:
cd spec && just

release:
./release.sh
zig build release {{flags}}
21 changes: 8 additions & 13 deletions release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@

set -e

targets=(
x86_64-linux-musl
aarch64-linux-musl
x86_64-macos
aarch64-macos
x86_64-windows
aarch64-windows
)
rm -rf "zig-out/release"
rm -rf "zig-out/archives"

zig build release -Doptimize=ReleaseSafe --prefix "zig-out/release" --verbose

mkdir -p "zig-out/archives"

for target in ${targets[@]}; do
echo "building $target..."
mkdir -p "zig-out/$target"
zig build -Dtarget=$target -Doptimize=ReleaseSafe --prefix "zig-out/$target"
(cd "zig-out/$target/" && zip -r "../archives/$target.zip" *)
for target_path in zig-out/release/*; do
target=$(basename "$target_path")
echo "archiving $target..."
(cd "zig-out/release/$target/" && zip -r "../../archives/$target.zip" *)
done
54 changes: 27 additions & 27 deletions src/Document.zig
Original file line number Diff line number Diff line change
Expand Up @@ -83,27 +83,14 @@ pub fn nodeRange(self: *@This(), node: u32) !lsp.Range {
};
}

pub fn wordUnderCursor(self: *@This(), cursor: lsp.Position) []const u8 {
const offset = self.utf8FromPosition(cursor);

var start = offset;
var end = offset;

const bytes = self.contents.items;
while (start > 0 and isIdentifierChar(bytes[start - 1])) start -= 1;
while (end < bytes.len and isIdentifierChar(bytes[end])) end += 1;

return bytes[start..end];
}

/// Return the node right under the cursor.
pub fn nodeUnderCursor(self: *@This(), cursor: lsp.Position) !?u32 {
pub fn identifierUnderCursor(self: *@This(), cursor: lsp.Position) !?u32 {
const offset = self.utf8FromPosition(cursor);
const parsed = try self.parseTree();
const tree = parsed.tree;

for (0.., tree.nodes.items(.tag), tree.nodes.items(.span)) |index, tag, span| {
if (tag.isToken() and span.start <= offset and offset < span.end) {
if (tag == .identifier and span.start <= offset and offset <= span.end) {
return @intCast(index);
}
}
Expand All @@ -112,7 +99,7 @@ pub fn nodeUnderCursor(self: *@This(), cursor: lsp.Position) !?u32 {
}

/// Return the node closest to left of the cursor.
pub fn nodeBeforeCursor(self: *@This(), cursor: lsp.Position) !?u32 {
pub fn tokenBeforeCursor(self: *@This(), cursor: lsp.Position) !?u32 {
const offset = self.utf8FromPosition(cursor);
const parsed = try self.parseTree();
const tree = parsed.tree;
Expand All @@ -126,7 +113,7 @@ pub fn nodeBeforeCursor(self: *@This(), cursor: lsp.Position) !?u32 {
if (span.start == span.end) continue;

// ignore tokens after the cursor
if (offset < span.start) continue;
if (offset <= span.start) continue;

if (span.end > best_end) {
// found a token further to the right
Expand All @@ -139,10 +126,6 @@ pub fn nodeBeforeCursor(self: *@This(), cursor: lsp.Position) !?u32 {
return best;
}

fn isIdentifierChar(c: u8) bool {
return std.ascii.isAlphanumeric(c) or c == '_';
}

pub fn parseTree(self: *@This()) !*const CompleteParseTree {
if (self.parse_tree) |*tree| return tree;
self.parse_tree = try CompleteParseTree.parseSource(
Expand All @@ -155,8 +138,11 @@ pub fn parseTree(self: *@This()) !*const CompleteParseTree {
pub const CompleteParseTree = struct {
arena_state: std.heap.ArenaAllocator.State,
tree: parse.Tree,
ignored: []parse.Token,
diagnostics: std.ArrayListUnmanaged(parse.Diagnostic),
ignored: []const parse.Token,
diagnostics: []const parse.Diagnostic,

// List of enabled extensions
extensions: []const []const u8,

pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
self.arena_state.promote(allocator).deinit();
Expand All @@ -166,22 +152,36 @@ pub const CompleteParseTree = struct {
var arena = std.heap.ArenaAllocator.init(parent_allocator);
errdefer arena.deinit();

const allocator = arena.allocator();
var diagnostics = std.ArrayList(parse.Diagnostic).init(arena.allocator());

var diagnostics = std.ArrayList(parse.Diagnostic).init(allocator);
var ignored = std.ArrayList(parse.Token).init(parent_allocator);
defer ignored.deinit();

const tree = try parse.parse(allocator, text, .{
const tree = try parse.parse(arena.allocator(), text, .{
.ignored = &ignored,
.diagnostics = &diagnostics,
});

var extensions = std.ArrayList([]const u8).init(arena.allocator());
errdefer extensions.deinit();

for (ignored.items) |token| {
const line = text[token.start..token.end];
switch (parse.parsePreprocessorDirective(line) orelse continue) {
.extension => |extension| {
const name = extension.name;
try extensions.append(line[name.start..name.end]);
},
else => continue,
}
}

return .{
.arena_state = arena.state,
.tree = tree,
.ignored = tree.ignored(),
.diagnostics = diagnostics.moveToUnmanaged(),
.diagnostics = diagnostics.items,
.extensions = extensions.items,
};
}
};
42 changes: 26 additions & 16 deletions src/Workspace.zig
Original file line number Diff line number Diff line change
Expand Up @@ -163,40 +163,50 @@ fn builtinCompletions(arena: std.mem.Allocator, spec: *const Spec) ![]lsp.Comple

try completions.append(.{
.label = variable.name,
.labelDetails = .{
.detail = try signature.toOwnedSlice(),
},
.labelDetails = .{ .detail = signature.items },
.kind = .variable,
.documentation = if (variable.description) |desc| .{
.kind = .markdown,
.value = try std.mem.join(arena, "\n\n", desc),
} else null,
.documentation = try itemDocumentation(arena, variable),
});
}

for (spec.functions) |function| {
var anonymous_signature = std.ArrayList(u8).init(arena);
var named_signature = std.ArrayList(u8).init(arena);
try writeFunctionSignature(function, anonymous_signature.writer(), .{ .names = false });

var named_signature = std.ArrayList(u8).init(arena);
try writeFunctionSignature(function, named_signature.writer(), .{ .names = true });

try completions.append(.{
.label = function.name,
.labelDetails = .{
.detail = try anonymous_signature.toOwnedSlice(),
},
.labelDetails = .{ .detail = anonymous_signature.items },
.kind = .function,
.detail = try named_signature.toOwnedSlice(),
.documentation = if (function.description) |desc| .{
.kind = .markdown,
.value = try std.mem.join(arena, "\n\n", desc),
} else null,
.detail = named_signature.items,
.documentation = try itemDocumentation(arena, function),
});
}

return completions.toOwnedSlice();
}

fn itemDocumentation(arena: std.mem.Allocator, item: anytype) !lsp.MarkupContent {
var documentation = std.ArrayList(u8).init(arena);

for (item.description orelse &.{}) |paragraph| {
try documentation.appendSlice(paragraph);
try documentation.appendSlice("\n\n");
}

if (item.extensions) |extensions| {
try documentation.appendSlice("```glsl\n");
for (extensions) |extension| {
try documentation.writer().print("#extension {s} : enable\n", .{extension});
}
try documentation.appendSlice("```\n");
}

return .{ .kind = .markdown, .value = try documentation.toOwnedSlice() };
}

fn writeFunctionSignature(
function: Spec.Function,
writer: anytype,
Expand Down
Loading

0 comments on commit 687922c

Please sign in to comment.