Skip to content

Conversation

@jiacai2050
Copy link
Owner

No description provided.

@gemini-code-assist
Copy link

Summary of Changes

Hello @jiacai2050, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request streamlines the project's documentation by replacing a symlinked README with a dedicated, informative file. Concurrently, it updates the project's version and dependency manifest, ensuring compatibility with a specified minimum Zig version and leveraging the latest version of the zig-curl library for improved stability or features.

Highlights

  • README Restructure: The symlinked README.org has been replaced with a new, comprehensive README.org file that provides a detailed introduction to the Zigcli project, including installation instructions and license information.
  • Project Version Update: The project version has been incremented from 0.3.0 to 0.3.1 in build.zig.zon.
  • Zig Version Requirement: A new minimum_zig_version field has been added to build.zig.zon, setting the requirement to 0.15.2.
  • Dependency Upgrade: The zig-curl dependency has been updated from version 0.3.1 to 0.3.2, along with its corresponding hash.
Ignored Files
  • Ignored by pattern: .github/workflows/** (3)
    • .github/workflows/CI.yml
    • .github/workflows/release.yml
    • .github/workflows/simargs.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly replaces the symlinked README.org with a proper file, which improves repository compatibility. The changes also include updating the build.zig.zon with a new version, a minimum Zig version requirement, and a dependency update. My review includes one suggestion to enhance the new README.org by re-adding the project badges that were present in the previous version, but with corrected links and updated information.

This commit fixes a critical logic error in the  parser to
ensure that patterns matching a directory also match all paths inside
that directory, aligning with official Git behavior. For example, a
pattern  should ignore the path .

The core change is in the  function. The base
case that handles an exhausted pattern now correctly returns  if
the path has remaining segments, signifying that the pattern is a valid
prefix of the path.

Key changes:
- Modified  to return  when the pattern
  is exhausted but the path is not, correctly implementing prefix matching.
- Added a new test case to verify that a pattern like  correctly
  matches a path like .
- The implementation continues to use  for robust and
  standard-compliant glob matching of individual path segments.

This fix ensures the parser is more compliant with the behavior
demonstrated by .
@jiacai2050
Copy link
Owner Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request primarily introduces a new gitignore parsing module, alongside dependency updates and clean-up of the README file. The changes to build.zig and build.zig.zon to incorporate the new module and update versions are correct.

My review focuses on the new src/mod/gitignore.zig file. While it's a solid implementation of gitignore parsing, I've identified a few areas for improvement:

  • A logic bug in pattern initialization that causes incorrect matching for directory-specific patterns (e.g., build/).
  • A memory management issue in the path matching loop due to how defer is used.
  • A couple of smaller issues related to API design (deinit) and test completeness.

I've provided detailed comments and suggestions for each of these points. Addressing them will make the new module more robust and correct.

Comment on lines 84 to 106
var path_parts = std.mem.splitScalar(u8, path, '/');
while (path_parts.next()) |part| {
const c_pattern = try std.fmt.allocPrintSentinel(self.allocator, "{s}", .{pattern_to_match}, 0);
defer self.allocator.free(c_pattern);
const c_path = try std.fmt.allocPrintSentinel(self.allocator, "{s}", .{part}, 0);
defer self.allocator.free(c_path);
if (c.fnmatch(c_pattern.ptr, c_path.ptr, c.FNM_PATHNAME) == 0) {
return true;
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are two issues in this loop:

  1. Inefficiency: c_pattern is allocated on every iteration, even though its value doesn't change. It should be allocated once before the loop.
  2. Memory Management: The defer self.allocator.free(c_path) statement is inside a while loop. In Zig, defer statements are executed at the end of the function, not the current block or loop iteration. This means that memory for c_path will be allocated in each iteration but only freed when the matches function returns, which can lead to high memory usage for paths with many components. You should free c_path manually at the end of each iteration or use a block with a defer inside it.
            const c_pattern = try std.fmt.allocPrintSentinel(self.allocator, "{s}", .{pattern_to_match}, 0);
            defer self.allocator.free(c_pattern);

            var path_parts = std.mem.splitScalar(u8, path, '/');
            while (path_parts.next()) |part| {
                if (try blk: {
                    const c_path = try std.fmt.allocPrintSentinel(self.allocator, "{s}", .{part}, 0);
                    defer self.allocator.free(c_path);
                    break :blk c.fnmatch(c_pattern.ptr, c_path.ptr, c.FNM_PATHNAME) == 0;
                }) {
                    return true;
                }
            }

Comment on lines 55 to 57
fn deinit(self: *Pattern, allocator: Allocator) void {
allocator.free(self.pattern);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The deinit function takes an allocator argument, but the Pattern struct already stores its own allocator (self.allocator). The convention in Zig is for deinit to use the allocator stored within the struct, so its signature should be fn deinit(self: *Pattern) void. This avoids redundancy and potential bugs if a different allocator is accidentally passed.

    fn deinit(self: *Pattern) void {
        self.allocator.free(self.pattern);
    }

// Test build/
try testing.expect(try gitignore.shouldIgnore("build", true));
try testing.expect(!(try gitignore.shouldIgnore("build", false)));
// This is incorrect according to gitignore spec. "build/" should only match "build" at the root.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This comment correctly points out a bug in the implementation regarding how patterns ending in / are handled. It's great that you've identified this! To make the tests more robust and prevent regressions, consider adding an assertion that would fail with the current buggy implementation but pass once it's fixed. For example, a pattern like build/ should not match a path like foo/build.

You could add a test case like this:

// This is incorrect according to gitignore spec. "build/" should only match "build" at the root.
try testing.expect(!(try gitignore.shouldIgnore("foo/build", true)));

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a gitignore module to the zigcli toolkit, updates project dependencies and tooling to Zig 0.15.2, and replaces the symlinked README with actual content.

  • Implements a new gitignore module with pattern matching support for .gitignore file syntax
  • Updates Zig version to 0.15.2 and curl dependency to v0.3.2
  • Converts README.org from a symlink to a standalone file with actual content

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/mod/gitignore.zig New module implementing .gitignore pattern parsing and path matching with fnmatch support
build.zig Adds gitignore module with libc linking, refactors test step to reuse existing modules
build.zig.zon Version bump to 0.3.1, adds minimum Zig version 0.15.2, updates curl dependency to v0.3.2, removes README.org from paths
README.org Replaces symlink with actual README content including project introduction and links
GEMINI.md Adds comprehensive project documentation for AI assistants covering architecture, build commands, and conventions
.tool-versions Updates Zig version from 0.15.1 to 0.15.2
.github/workflows/*.yml Removes hardcoded Zig version 0.15.1 to use default from setup-zig action

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 55 to 56
fn deinit(self: *Pattern, allocator: Allocator) void {
allocator.free(self.pattern);
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deinit method should use self.allocator instead of taking an allocator parameter, since the allocator is already stored in the struct during init. This would make the API more consistent and prevent potential mismatches between the allocator used for allocation and deallocation.

Suggested change
fn deinit(self: *Pattern, allocator: Allocator) void {
allocator.free(self.pattern);
fn deinit(self: *Pattern) void {
self.allocator.free(self.pattern);

Copilot uses AI. Check for mistakes.

The project is structured into two main parts:

* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`).
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module list is incomplete. The PR adds a gitignore module (as seen in build.zig line 51), but the documentation only mentions pretty-table and simargs. Update this to include gitignore in the list of reusable Zig modules.

Suggested change
* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`).
* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`, `gitignore`).

Copilot uses AI. Check for mistakes.
// Test build/
try testing.expect(try gitignore.shouldIgnore("build", true));
try testing.expect(!(try gitignore.shouldIgnore("build", false)));
// This is incorrect according to gitignore spec. "build/" should only match "build" at the root.
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment acknowledges that the implementation is incorrect according to the gitignore specification. The pattern "build/" should only match the "build" directory at the repository root, but the current implementation will match "build" anywhere in the tree. This is a known deviation from the gitignore spec that should be addressed or at least clearly documented as a limitation.

Copilot uses AI. Check for mistakes.
This commit introduces .gitignore support to the loc command and ensures
that symbolic links are ignored during directory traversal.

The core of this feature is a new, compliant .gitignore parser implemented
in src/mod/gitignore.zig. This parser has been refactored to use libc.fnmatch
for robust glob pattern matching.

Key changes:
- New 'gitignore' Module in 'src/mod/gitignore.zig'.
- The parser handles negation, directory-only patterns, anchored patterns,
  internal slashes, and wildcards ('*', '?', '**').
- Replaced custom glob matcher with 'libc.fnmatch'.
- The 'walk' function in 'loc.zig' now ignores symbolic links.
- Updated 'build.zig' for the new module and its tests.
@jiacai2050
Copy link
Owner Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request primarily focuses on removing a symlinked README.org, adding a new README.org and GEMINI.md for documentation, and introducing a new gitignore parsing module. The changes also include updating the Zig version and dependencies, and modifying the build script to accommodate the new module. While the new gitignore module is a great addition, I've found a critical compilation error in its implementation. Additionally, there are a couple of minor issues: one in the new GEMINI.md documentation file and a typo in a test name within the gitignore module. Addressing these points will improve the quality and correctness of the pull request.

if (trimmed.len == 0 or trimmed[0] == '#') {
continue;
}
try self.patterns.append(allocator, try Pattern.init(allocator, trimmed));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The call to self.patterns.append is incorrect. The std.ArrayList.append function does not take an allocator as its first argument. This will result in a compilation error. Please remove the allocator argument from this call.

            try self.patterns.append(try Pattern.init(allocator, trimmed));


The project is structured into two main parts:

* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The list of reusable modules under the Architecture section is incomplete. It's missing the newly added gitignore module. Keeping this documentation updated is important for project clarity.

Suggested change
* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`).
* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`, `gitignore`).

try testing.expect(try gitignore.shouldIgnore("foo/bar/123", false));
}

test "specal case, rule /" {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a typo in the test name. specal should be special.

test "special case, rule /" {

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 172 to +179
const path = comptime source.path();
const module = b.modules.get(name) orelse b.createModule(.{
.root_source_file = b.path(path ++ "/" ++ name ++ ".zig"),
.target = target,
});
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gitignore module requires linking libc (as specified in line 54), but when building tests through buildTestStep, if the module is not found in b.modules.get(name), it falls back to creating a new module without the link_libc flag. This will cause the gitignore tests to fail since they depend on fnmatch.h. The fallback should either copy the module's properties or always use the module from b.modules for modules that require special configuration.

Suggested change
const path = comptime source.path();
const module = b.modules.get(name) orelse b.createModule(.{
.root_source_file = b.path(path ++ "/" ++ name ++ ".zig"),
.target = target,
});
const module = b.modules.get(name) orelse @panic("Module '" ++ name ++ "' not found in b.modules. Please ensure it is added with all required configuration before building tests.");

Copilot uses AI. Check for mistakes.

The project is structured into two main parts:

* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`).
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation lists only pretty-table and simargs as modules, but the new gitignore module has been added in this PR and should be included in this list.

Suggested change
* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`).
* **`src/mod`:** Contains reusable Zig modules (`pretty-table`, `simargs`, `gitignore`).

Copilot uses AI. Check for mistakes.
.negation = negation,
.is_dir = is_dir,
.anchored_to_root = anchored_to_root,
.contains_slash = std.mem.indexOf(u8, p, "/") != null or std.mem.indexOf(u8, p, "**") != null,
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition std.mem.indexOf(u8, p, "**") != null in determining contains_slash seems incorrect. The ** wildcard is a gitignore feature, but it's not the same as containing a slash. A pattern like **foo without any slashes should probably not have contains_slash set to true. According to gitignore rules, contains_slash should determine whether the pattern is matched against the full path or just the basename. Consider whether this logic correctly implements the gitignore specification.

Suggested change
.contains_slash = std.mem.indexOf(u8, p, "/") != null or std.mem.indexOf(u8, p, "**") != null,
.contains_slash = std.mem.indexOf(u8, p, "/") != null,

Copilot uses AI. Check for mistakes.
jiacai2050 and others added 2 commits November 30, 2025 18:55
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@jiacai2050 jiacai2050 changed the title fix: remove symlinked README feat: add gitignore module Nov 30, 2025
@jiacai2050 jiacai2050 merged commit edd29d2 into main Nov 30, 2025
9 of 10 checks passed
@jiacai2050 jiacai2050 deleted the fix-symlink branch November 30, 2025 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants