Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a format guard #1033

Closed
wants to merge 1 commit into from
Closed

Add a format guard #1033

wants to merge 1 commit into from

Conversation

balayette
Copy link

zig fmt now ignores all files that start with // zig fmt: skip
fixes #1030

defer file.close();
const size = try file.getEndPos();

var adaptater = io.FileInStream.init(&file);
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you meant adapter.

start_index = try adaptater.stream.read(source_code);
if(mem.eql(u8, source_code, "// zig fmt: skip")){
try stderr.print("won't format {}\n", file_path);
allocator.free(source_code);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need this free? Won't it happen at line 756? If you want to handle the potential stderr error, then use errdefer allocator.free(source_code), or even better, move the defer allocator.free(source_code) to before this new code.

Copy link
Author

Choose a reason for hiding this comment

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

I believe that continue on the next line will jump back to the top of the loop, without executing line 756.
I didn't move it to the beginning, because in the event that the allocation fails, I assume that source_code would still be undefined, and I didn't want to free(undefined).
I may be mistaken.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since it is a fixed size, one thing you could do here is read into a local scope [16]u8 and if it doesn't match seek(0) on the file and then let the actual work happen. Seems like it would be cleaner since there's just one check and an early continue.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I actually planned on doing that but couldn't find a seek function. Well, I checked again and found seekTo in file.zig and I now feel stupid 😃

defer allocator.free(source_code);

_ = try adaptater.stream.read(source_code[start_index..]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this an error if _ = not used?

Copy link
Author

Choose a reason for hiding this comment

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

read returns the number of bytes read, which we don't care about in this case.

@andrewrk
Copy link
Member

andrewrk commented Jun 1, 2018

Thanks for the PR. I think there's a better way to do this. For one, I want to use @monouser7dig's idea to have a feature equivalent to clang-format where you can turn on and off the formatter for sections.

My original idea, which you coded up, has the problem that if there were ever another reason to put meta-information in a comment like this, which comment is "first" would fight with each other.

So the approach I would want to take on this issue is to have the support be in std.zig.render. It would look for a LineComment token before every top level declaration. If it found one that disabled formatting, then it would scan for the next LineComment that re-enables formatting (or EOF), and then directly copy bytes from the source buffer to the output stream, and then skip over top level declarations until it was after the token that re-enabled formatting.

@balayette
Copy link
Author

balayette commented Jun 1, 2018

Thanks for the detailed feedback! I fully agree!
I didn't write this as a comprehensive solution, and I expected your answer.
However, it allows completely skipping over large files and not load them in memory, which seemed to be a concern, seeing that you mentioned file sizes in #1030.

Thanks

@andrewrk
Copy link
Member

andrewrk commented Jun 1, 2018

However, it allows completely skipping over large files and not load them in memory, which seemed to be a concern, seeing that you mentioned file sizes in #1030.

That's true! And I appreciate the effort. However, here is one of the Zen of Zig items:

  • Avoid local maximums.

How that can be applied here is that we can focus our energy on the long-term solution that will solve this use case, rather than a temporary bandage.

That being said, the fact that you put the effort into this pull request means that I will leave it open until the problem is solved. And open pull requests are very motivating to resolve.

@tiehuis
Copy link
Member

tiehuis commented Jun 1, 2018

One other thing that needs to be considered is that we accept shebangs for zig run so this wouldn't be able to be put on the first line in every case. I think we'd need to handle a zig fmt: off (and maybe zig fmt: on) anywhere in a source file. Andrew seems to have covered this above so that looks fine.

@balayette
Copy link
Author

So the approach I would want to take on this issue is to have the support be in std.zig.render. It would look for a LineComment token before every top level declaration. If it found one that disabled formatting, then it would scan for the next LineComment that re-enables formatting (or EOF), and then directly copy bytes from the source buffer to the output stream, and then skip over top level declarations until it was after the token that re-enabled formatting.

That wouldn't give much control over formatting, because formatting could only be turned off for entire top level declarations. clang-format allows enabling and disabling formatting anywhere in a file, not only before top level declarations.

clang-format also keeps track of blocks and indentation even when it is disabled :

$ cat test.c           
int a = 2;
// clang-format off
     if(a == 2){
// clang-format on
a = 3;
}

$ clang-format ./test.c
int a = 2;
// clang-format off
     if(a == 2){
  // clang-format on
  a = 3;
}

Here, it didn't format the if, but it did indent a = 3;

I fear that heavy refactoring will be needed and that simply scanning top level declaratinos isn't enough. (That is, if we want feature parity with clang-format)

@andrewrk andrewrk closed this in d21a192 Jun 4, 2018
@andrewrk
Copy link
Member

andrewrk commented Jun 4, 2018

We don't need feature parity with clang-format. I don't think the above code looks very good; the ability to produce such code is not something I will miss. I consider this issue resolved now.

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.

have zig fmt notice a special comment that tells it to skip a source file
5 participants