mirror of
https://codeberg.org/ziglings/exercises.git
synced 2026-07-29 02:35:15 +00:00
Compare commits
33 Commits
a463aafb91
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f39b462659 | |||
| a2eee9d52f | |||
| 248093a2de | |||
| 004ea3b3ae | |||
| c85daab1a1 | |||
| f6c3e4edc4 | |||
| a5ed7b636b | |||
| ba99eea43b | |||
| 708436c63d | |||
| e65b359055 | |||
| 719f7f0740 | |||
| 9a1ff49206 | |||
| 89fe65c158 | |||
| 6e34e835e0 | |||
| a03b676bed | |||
| 151db7bcd4 | |||
| b39f223b8c | |||
| e932615712 | |||
| 98b831aec4 | |||
| f69c79bcb6 | |||
| 951351aa2e | |||
| e1bf750b03 | |||
| 7e2cf64ae8 | |||
| 4f5a26345f | |||
| 4f240aaefa | |||
| d093f37e1e | |||
| fdf47e3b8c | |||
| 12c8511412 | |||
| e55204d342 | |||
| fe465a466e | |||
| f6514ebb13 | |||
| 529b294cc3 | |||
| e928d2c7b1 |
+1
-1
@@ -95,7 +95,7 @@ interface. Specifically:
|
|||||||
eternal Ziglings contributor glory is yours!
|
eternal Ziglings contributor glory is yours!
|
||||||
|
|
||||||
|
|
||||||
## Licence
|
## License
|
||||||
|
|
||||||
If you submit your contribution to the repository/project,
|
If you submit your contribution to the repository/project,
|
||||||
you agree that your contribution will be licensed under
|
you agree that your contribution will be licensed under
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ pub fn build(b: *Build) !void {
|
|||||||
const run = b.addRunArtifact(elrond);
|
const run = b.addRunArtifact(elrond);
|
||||||
run.addArg(b.fmt("--zig={s}", .{b.graph.zig_exe}));
|
run.addArg(b.fmt("--zig={s}", .{b.graph.zig_exe}));
|
||||||
run.addArg(b.fmt("--work-path={s}", .{work_path}));
|
run.addArg(b.fmt("--work-path={s}", .{work_path}));
|
||||||
|
run.addArg(b.fmt("--root-path={s}", .{b.root.root_dir.path.?}));
|
||||||
|
|
||||||
if (exno) |n| {
|
if (exno) |n| {
|
||||||
run.addArg(b.fmt("--only={d}", .{n}));
|
run.addArg(b.fmt("--only={d}", .{n}));
|
||||||
|
|||||||
@@ -26,8 +26,13 @@ pub fn main() void {
|
|||||||
// (Problem 2)
|
// (Problem 2)
|
||||||
// Please set this array using repetition.
|
// Please set this array using repetition.
|
||||||
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
|
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
|
||||||
const bit_pattern_unit = [_]u8{ ??? };
|
const bit_pattern_unit = ???;
|
||||||
const bit_pattern: [3 * bit_pattern_unit.len]u8 = @bitCast(@as([3][bit_pattern_unit.len]u8, @splat(bit_pattern_unit)));
|
|
||||||
|
// How long should the bit pattern be?
|
||||||
|
const len = ???;
|
||||||
|
|
||||||
|
// For now, don't worry about the use of SIMD.
|
||||||
|
const bit_pattern: [len]u8 = std.simd.repeat(len, bit_pattern_unit);
|
||||||
|
|
||||||
// Okay, that's all of the problems. Let's see the results.
|
// Okay, that's all of the problems. Let's see the results.
|
||||||
//
|
//
|
||||||
@@ -53,3 +58,12 @@ pub fn main() void {
|
|||||||
|
|
||||||
std.debug.print("\n", .{});
|
std.debug.print("\n", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For the curious:
|
||||||
|
//
|
||||||
|
// The `std.simd.repeat` function takes a target length and a pattern,
|
||||||
|
// and returns a vector filled with that pattern repeated to the
|
||||||
|
// desired length.
|
||||||
|
//
|
||||||
|
// For example, `repeat(5, [_]u8{1, 2})` will return a vector
|
||||||
|
// equivalent to `.{1, 2, 1, 2, 1}`.
|
||||||
|
|||||||
@@ -30,3 +30,11 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
// We just learned of a single statement which can accomplish this.
|
// We just learned of a single statement which can accomplish this.
|
||||||
stdout.print("Hello world!\n", .{});
|
stdout.print("Hello world!\n", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now you must be thinking "Why would I need to do this instead of good
|
||||||
|
// old 'std.debug.print()'?", but here's what you need to understand:
|
||||||
|
// 'std.debug.print()' prints its output to stderr, while the stdout_writer
|
||||||
|
// approach prints to stdout.
|
||||||
|
// A common practice is to pipe output of a command to other commands,
|
||||||
|
// and in order for the piping to work, those commands expect their input
|
||||||
|
// to come from stdout, not stderr.
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ pub fn main() void {
|
|||||||
print("He has room in his heart for:", .{});
|
print("He has room in his heart for:", .{});
|
||||||
|
|
||||||
// `field_names` is a slice of strings and it holds the names of the struct's fields
|
// `field_names` is a slice of strings and it holds the names of the struct's fields
|
||||||
// `field_types` is a slice of strings and it holds the types of the struct's fields,
|
// `field_types` is a slice of types and it holds the types of the struct's fields,
|
||||||
// it is guaranteed to be the same length as `field_names`
|
// it is guaranteed to be the same length as `field_names`
|
||||||
const field_names = @typeInfo(Narcissus).@"struct".field_names;
|
const field_names = @typeInfo(Narcissus).@"struct".field_names;
|
||||||
const field_types = @typeInfo(Narcissus).@"struct".field_types;
|
const field_types = @typeInfo(Narcissus).@"struct".field_types;
|
||||||
|
|||||||
@@ -75,10 +75,10 @@ pub fn main() !void {
|
|||||||
std.debug.print("Starting work...\n", .{});
|
std.debug.print("Starting work...\n", .{});
|
||||||
|
|
||||||
// These curly braces are very important, they are necessary
|
// These curly braces are very important, they are necessary
|
||||||
// to enclose the area where the threads are called.
|
// to enclose the area where the threads are called and joined.
|
||||||
// Without these braces, the program would not wait for the
|
// With these braces, the program will block and wait for all threads
|
||||||
// end of the threads and they would continue to run beyond the
|
// to finish right at the closing brace of this block, ensuring
|
||||||
// end of the program.
|
// "Zig is cool!" is always printed last.
|
||||||
{
|
{
|
||||||
// Now we start the first thread, with the number as parameter
|
// Now we start the first thread, with the number as parameter
|
||||||
const handle = try std.Thread.spawn(.{}, thread_function, .{1});
|
const handle = try std.Thread.spawn(.{}, thread_function, .{1});
|
||||||
@@ -102,8 +102,7 @@ pub fn main() !void {
|
|||||||
try io.sleep(std.Io.Duration.fromMilliseconds(400), .awake);
|
try io.sleep(std.Io.Duration.fromMilliseconds(400), .awake);
|
||||||
std.debug.print("Some weird stuff, after starting the threads.\n", .{});
|
std.debug.print("Some weird stuff, after starting the threads.\n", .{});
|
||||||
}
|
}
|
||||||
// After we have left the closed area, we wait until
|
// The threads are guaranteed to be finished by the time we reach here.
|
||||||
// the threads have run through, if this has not yet been the case.
|
|
||||||
std.debug.print("Zig is cool!\n", .{});
|
std.debug.print("Zig is cool!\n", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
// We will not go into the formula and its derivation in detail, but
|
// We will not go into the formula and its derivation in detail, but
|
||||||
// will deal with the series straight away:
|
// will deal with the series straight away:
|
||||||
//
|
//
|
||||||
// 4 4 4 4 4
|
// 4 4 4 4 4
|
||||||
// PI = --- - --- + --- - --- + --- ...
|
// PI = + --- - --- + --- - --- + --- ...
|
||||||
// 1 3 5 7 9
|
// 1 3 5 7 9
|
||||||
//
|
//
|
||||||
// As you can clearly see, the series starts with the whole number 4 and
|
// As you can clearly see, the series starts with the whole number 4 and
|
||||||
// approaches the circle number by subtracting and adding smaller and
|
// approaches the circle number by subtracting and adding smaller and
|
||||||
@@ -71,27 +71,28 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const count = 1_000_000_000;
|
const count = 500_000_000;
|
||||||
|
|
||||||
var pi_plus: f64 = 0;
|
var pi_plus: f64 = 0;
|
||||||
var pi_minus: f64 = 0;
|
var pi_minus: f64 = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
// First thread to calculate the plus numbers.
|
// First thread to calculate the plus numbers.
|
||||||
const handle1 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_plus, 5, count });
|
const handle1 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_plus, 1, count });
|
||||||
defer handle1.join();
|
defer handle1.join();
|
||||||
|
|
||||||
// Second thread to calculate the minus numbers.
|
// Second thread to calculate the minus numbers.
|
||||||
???
|
???
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we add up the results.
|
// Here we add up the results.
|
||||||
std.debug.print("PI ≈ {d:.8}\n", .{4 + pi_plus - pi_minus});
|
std.debug.print("PI ≈ {d:.8} (error = {e:.1})\n", .{ pi_plus - pi_minus, std.math.pi - (pi_plus - pi_minus) });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thread_pi(pi: *f64, begin: u64, end: u64) !void {
|
fn thread_pi(pi: *f64, begin: u64, count: u64) !void {
|
||||||
var n: u64 = begin;
|
for (0..count) |i| {
|
||||||
while (n < end) : (n += 4) {
|
const term = 4 / @as(f64, @floatFromInt(begin + 4 * i));
|
||||||
pi.* += 4 / @as(f64, @floatFromInt(n));
|
pi.* += term;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If you wish, you can increase the number of loop passes, which
|
// If you wish, you can increase the number of loop passes, which
|
||||||
@@ -103,8 +104,14 @@ fn thread_pi(pi: *f64, begin: u64, end: u64) !void {
|
|||||||
// is created. Otherwise the debug functions slow down the speed
|
// is created. Otherwise the debug functions slow down the speed
|
||||||
// to such an extent that seconds become minutes during execution.
|
// to such an extent that seconds become minutes during execution.
|
||||||
//
|
//
|
||||||
|
// You can use the following command to build and run this
|
||||||
|
// exercise with the "ReleaseFast" flag:
|
||||||
|
//
|
||||||
|
// zig run exercises/108_threading2.zig -O ReleaseFast
|
||||||
|
//
|
||||||
// And you should remove the formatting restriction in "print",
|
// And you should remove the formatting restriction in "print",
|
||||||
// otherwise you will not be able to see the additional digits.
|
// otherwise you will not be able to see the additional digits.
|
||||||
//
|
//
|
||||||
// If count = 10_000_000_000_000 you should see the following:
|
// If count = 2_500_000_000_000, you should see the following:
|
||||||
// 3.141592653589
|
// 3.141592653589
|
||||||
|
// (after waiting on the order of 1000 seconds, or 17 minutes)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
// wait a minute...
|
// wait a minute...
|
||||||
// opening a directory might fail!
|
// opening a directory might fail!
|
||||||
// what should we do here?
|
// what should we do here?
|
||||||
var output_dir: std.Io.Dir = try cwd.openDir(io, "output", .{});
|
var output_dir: std.Io.Dir = cwd.openDir(io, "output", .{});
|
||||||
defer output_dir.close(io);
|
defer output_dir.close(io);
|
||||||
|
|
||||||
// we try to open the file `zigling.txt`,
|
// we try to open the file `zigling.txt`,
|
||||||
|
|||||||
@@ -145,3 +145,7 @@ pub fn main() void {
|
|||||||
print("Max difference (old fn): {d: >5.3}\n", .{mpd_old});
|
print("Max difference (old fn): {d: >5.3}\n", .{mpd_old});
|
||||||
print("Max difference (new fn): {d: >5.3}\n", .{mpd_new});
|
print("Max difference (new fn): {d: >5.3}\n", .{mpd_new});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Another cool feature of Vectors is repeating patterns.
|
||||||
|
// Remember the arrays exercise from earlier where we created an array
|
||||||
|
// by repeating a pattern? See `005_arrays2.zig`.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- exercises/005_arrays2.zig 2026-05-04 16:26:32.778330847 +0200
|
--- exercises/005_arrays2.zig 2026-06-27 09:03:29.918124920 +0000
|
||||||
+++ answers/005_arrays2.zig 2026-05-04 16:26:13.082917974 +0200
|
+++ answers/005_arrays2.zig 2026-06-27 09:01:13.162138431 +0000
|
||||||
@@ -21,12 +21,12 @@
|
@@ -21,15 +21,15 @@
|
||||||
// (Problem 1)
|
// (Problem 1)
|
||||||
// Please set this array concatenating the two arrays above.
|
// Please set this array concatenating the two arrays above.
|
||||||
// It should result in: 1 3 3 7
|
// It should result in: 1 3 3 7
|
||||||
@@ -10,8 +10,12 @@
|
|||||||
// (Problem 2)
|
// (Problem 2)
|
||||||
// Please set this array using repetition.
|
// Please set this array using repetition.
|
||||||
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
|
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
|
||||||
- const bit_pattern_unit = [_]u8{ ??? };
|
- const bit_pattern_unit = ???;
|
||||||
+ const bit_pattern_unit = [_]u8{ 1, 0, 0, 1 };
|
+ const bit_pattern_unit = [_]u8{ 1, 0, 0, 1 };
|
||||||
const bit_pattern: [3 * bit_pattern_unit.len]u8 = @bitCast(@as([3][bit_pattern_unit.len]u8, @splat(bit_pattern_unit)));
|
|
||||||
|
|
||||||
// Okay, that's all of the problems. Let's see the results.
|
// How long should the bit pattern be?
|
||||||
|
- const len = ???;
|
||||||
|
+ const len = 3 * bit_pattern_unit.len;
|
||||||
|
|
||||||
|
// For now, don't worry about the use of SIMD.
|
||||||
|
const bit_pattern: [len]u8 = std.simd.repeat(len, bit_pattern_unit);
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
--- exercises/026_hello2.zig 2026-01-09 22:51:45.803358789 +0100
|
--- exercises/026_hello2.zig 2026-07-01 16:27:18.674459266 +0200
|
||||||
+++ answers/026_hello2.zig 2026-01-09 22:50:46.016166527 +0100
|
+++ answers/026_hello2.zig 2026-07-01 16:27:08.579220702 +0200
|
||||||
@@ -28,5 +28,5 @@
|
@@ -28,7 +28,7 @@
|
||||||
// to be able to pass it up as a return value of main().
|
// to be able to pass it up as a return value of main().
|
||||||
//
|
//
|
||||||
// We just learned of a single statement which can accomplish this.
|
// We just learned of a single statement which can accomplish this.
|
||||||
- stdout.print("Hello world!\n", .{});
|
- stdout.print("Hello world!\n", .{});
|
||||||
+ try stdout.print("Hello world!\n", .{});
|
+ try stdout.print("Hello world!\n", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now you must be thinking "Why would I need to do this instead of good
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
--- exercises/036_enums2.zig 2023-10-03 22:15:22.122241138 +0200
|
--- exercises/036_enums2.zig 2026-07-21 20:48:50.596099259 +0200
|
||||||
+++ answers/036_enums2.zig 2023-10-05 20:04:07.002765884 +0200
|
+++ answers/036_enums2.zig 2026-07-21 20:50:14.726826859 +0200
|
||||||
@@ -31,7 +31,7 @@
|
@@ -31,7 +31,7 @@
|
||||||
const Color = enum(u32) {
|
const Color = enum(u32) {
|
||||||
red = 0xff0000,
|
red = 0xff0000,
|
||||||
@@ -18,9 +18,11 @@
|
|||||||
\\</p>
|
\\</p>
|
||||||
\\
|
\\
|
||||||
, .{
|
, .{
|
||||||
@intFromEnum(Color.red),
|
- @intFromEnum(Color.red),
|
||||||
@intFromEnum(Color.green),
|
- @intFromEnum(Color.green),
|
||||||
- @intFromEnum(???), // Oops! We're missing something!
|
- @intFromEnum(???), // Oops! We're missing something!
|
||||||
+ @intFromEnum(Color.blue), // Oops! We're missing something!
|
+ @backingInt(Color.red),
|
||||||
|
+ @backingInt(Color.green),
|
||||||
|
+ @backingInt(Color.blue), // Oops! We're missing something!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
--- exercises/108_threading2.zig 2026-04-14 06:44:18.848246237 +0200
|
--- exercises/108_threading2.zig 2026-06-29 23:25:53
|
||||||
+++ answers/108_threading2.zig 2026-04-14 08:15:30.894485037 +0200
|
+++ answers/108_threading2.zig 2026-06-29 23:25:25
|
||||||
@@ -81,8 +81,8 @@
|
@@ -82,7 +82,8 @@
|
||||||
defer handle1.join();
|
defer handle1.join();
|
||||||
|
|
||||||
// Second thread to calculate the minus numbers.
|
// Second thread to calculate the minus numbers.
|
||||||
- ???
|
- ???
|
||||||
-
|
|
||||||
+ const handle2 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_minus, 3, count });
|
+ const handle2 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_minus, 3, count });
|
||||||
+ defer handle2.join();
|
+ defer handle2.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we add up the results.
|
// Here we add up the results.
|
||||||
std.debug.print("PI ≈ {d:.8}\n", .{4 + pi_plus - pi_minus});
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
--- exercises/109_files.zig 2026-03-20 19:23:48.874150121 +0100
|
--- exercises/109_files.zig 2026-06-29 17:08:04.124224900 +0000
|
||||||
+++ answers/109_files.zig 2026-04-02 10:51:15.813831695 +0200
|
+++ answers/109_files.zig 2026-06-29 17:13:20.696220533 +0000
|
||||||
@@ -41,7 +41,7 @@
|
@@ -41,7 +41,7 @@
|
||||||
// by doing nothing
|
// by doing nothing
|
||||||
//
|
//
|
||||||
@@ -9,6 +9,15 @@
|
|||||||
// if there's any other unexpected error we just propagate it through
|
// if there's any other unexpected error we just propagate it through
|
||||||
else => return e,
|
else => return e,
|
||||||
};
|
};
|
||||||
|
@@ -50,7 +50,7 @@
|
||||||
|
// wait a minute...
|
||||||
|
// opening a directory might fail!
|
||||||
|
// what should we do here?
|
||||||
|
- var output_dir: std.Io.Dir = cwd.openDir(io, "output", .{});
|
||||||
|
+ var output_dir: std.Io.Dir = try cwd.openDir(io, "output", .{});
|
||||||
|
defer output_dir.close(io);
|
||||||
|
|
||||||
|
// we try to open the file `zigling.txt`,
|
||||||
@@ -61,7 +61,7 @@
|
@@ -61,7 +61,7 @@
|
||||||
// but here we are not yet done writing to the file
|
// but here we are not yet done writing to the file
|
||||||
// if only there were a keyword in Zig that
|
// if only there were a keyword in Zig that
|
||||||
|
|||||||
+72
-55
@@ -19,12 +19,28 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
const Io = std.Io;
|
||||||
|
const File = Io.File;
|
||||||
const Process = std.process;
|
const Process = std.process;
|
||||||
|
const Terminal = std.Io.Terminal;
|
||||||
const print = std.debug.print;
|
const print = std.debug.print;
|
||||||
const cutPrefix = std.mem.cutPrefix;
|
const cutPrefix = std.mem.cutPrefix;
|
||||||
|
|
||||||
const progress_filename = ".progress.txt";
|
const progress_filename = ".progress.txt";
|
||||||
|
|
||||||
|
const no_colors_help =
|
||||||
|
\\Colors are not available. Check the NO_COLOR environ variable.
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
|
||||||
|
const windows_colors_help =
|
||||||
|
\\Windows colors are not supported.
|
||||||
|
\\Install Windows Terminal or update to a more recent Windows version.
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
|
||||||
pub const logo =
|
pub const logo =
|
||||||
\\ _ _ _
|
\\ _ _ _
|
||||||
\\ ___(_) __ _| (_)_ __ __ _ ___
|
\\ ___(_) __ _| (_)_ __ __ _ ___
|
||||||
@@ -109,41 +125,23 @@ const Context = struct {
|
|||||||
arena: std.mem.Allocator,
|
arena: std.mem.Allocator,
|
||||||
zig_exe: []const u8,
|
zig_exe: []const u8,
|
||||||
work_path: []const u8,
|
work_path: []const u8,
|
||||||
|
root_path: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Error = error{Failed};
|
const Error = error{Failed};
|
||||||
|
|
||||||
// Ansi colors.
|
var stderr_term_mode: Terminal.Mode = .no_color;
|
||||||
var use_color_escapes = false;
|
|
||||||
var red_text: []const u8 = "";
|
|
||||||
var red_bold_text: []const u8 = "";
|
|
||||||
var red_dim_text: []const u8 = "";
|
|
||||||
var green_text: []const u8 = "";
|
|
||||||
var yellow_text: []const u8 = "";
|
|
||||||
var bold_text: []const u8 = "";
|
|
||||||
var reset_text: []const u8 = "";
|
|
||||||
|
|
||||||
fn setupColors(io: std.Io) void {
|
// Ansi colors.
|
||||||
use_color_escapes = false;
|
const C = struct {
|
||||||
const stderr = std.Io.File.stderr();
|
var red: []const u8 = "\x1b[31m";
|
||||||
if (stderr.supportsAnsiEscapeCodes(io)) |ok| {
|
var red_bold: []const u8 = "\x1b[31;1m";
|
||||||
if (ok) use_color_escapes = true;
|
var red_dim: []const u8 = "\x1b[31;2m";
|
||||||
} else |_| {}
|
var green: []const u8 = "\x1b[32m";
|
||||||
if (!use_color_escapes and builtin.os.tag == .windows) {
|
var yellow: []const u8 = "\x1b[33m";
|
||||||
if (stderr.enableAnsiEscapeCodes(io)) {
|
var bold: []const u8 = "\x1b[1m";
|
||||||
use_color_escapes = true;
|
var reset: []const u8 = "\x1b[0m";
|
||||||
} else |_| {}
|
};
|
||||||
}
|
|
||||||
if (use_color_escapes) {
|
|
||||||
red_text = "\x1b[31m";
|
|
||||||
red_bold_text = "\x1b[31;1m";
|
|
||||||
red_dim_text = "\x1b[31;2m";
|
|
||||||
green_text = "\x1b[32m";
|
|
||||||
yellow_text = "\x1b[33m";
|
|
||||||
bold_text = "\x1b[1m";
|
|
||||||
reset_text = "\x1b[0m";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main(init: std.process.Init) !void {
|
pub fn main(init: std.process.Init) !void {
|
||||||
const io = init.io;
|
const io = init.io;
|
||||||
@@ -152,24 +150,51 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
var args_it = try init.minimal.args.iterateAllocator(arena);
|
var args_it = try init.minimal.args.iterateAllocator(arena);
|
||||||
if (!args_it.skip()) @panic("expected self arg");
|
if (!args_it.skip()) @panic("expected self arg");
|
||||||
|
|
||||||
setupColors(io);
|
const stderr = File.stderr();
|
||||||
|
|
||||||
|
// Setup colors.
|
||||||
|
const NO_COLOR = try init.minimal.environ.containsUnempty(arena, "NO_COLOR");
|
||||||
|
const CLICOLOR_FORCE = try init.minimal.environ.containsUnempty(arena, "CLICOLOR_FORCE");
|
||||||
|
|
||||||
|
const term_mode = try Terminal.Mode.detect(io, stderr, NO_COLOR, CLICOLOR_FORCE);
|
||||||
|
stderr_term_mode = term_mode;
|
||||||
|
|
||||||
|
// Show help in case colors are not available or not supported.
|
||||||
|
switch (term_mode) {
|
||||||
|
.no_color => print(no_colors_help, .{}),
|
||||||
|
.escape_codes => {},
|
||||||
|
.windows_api => print(windows_colors_help, .{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (term_mode == .no_color) {
|
||||||
|
C.red = "";
|
||||||
|
C.red_bold = "";
|
||||||
|
C.red_dim = "";
|
||||||
|
C.green = "";
|
||||||
|
C.yellow = "";
|
||||||
|
C.bold = "";
|
||||||
|
C.reset = "";
|
||||||
|
}
|
||||||
|
|
||||||
if (!validateExercises()) std.process.exit(1);
|
if (!validateExercises()) std.process.exit(1);
|
||||||
|
|
||||||
var zig_exe: []const u8 = "zig";
|
var zig_exe: []const u8 = "zig";
|
||||||
var work_path: []const u8 = "exercises";
|
var work_path: []const u8 = "exercises";
|
||||||
|
var root_path: []const u8 = "";
|
||||||
var mode: Mode = .normal;
|
var mode: Mode = .normal;
|
||||||
var only_n: ?usize = null;
|
var only_n: ?usize = null;
|
||||||
var start_n: ?usize = null;
|
var start_n: ?usize = null;
|
||||||
|
|
||||||
while (args_it.next()) |arg| {
|
while (args_it.next()) |arg| {
|
||||||
if (std.mem.eql(u8, arg, "--logo")) {
|
if (std.mem.eql(u8, arg, "--logo")) {
|
||||||
print("{s}{s}{s}", .{ yellow_text, logo, reset_text });
|
print("{s}{s}{s}", .{ C.yellow, logo, C.reset });
|
||||||
return;
|
return;
|
||||||
} else if (cutPrefix(u8, arg, "--zig=")) |v| {
|
} else if (cutPrefix(u8, arg, "--zig=")) |v| {
|
||||||
zig_exe = v;
|
zig_exe = v;
|
||||||
} else if (cutPrefix(u8, arg, "--work-path=")) |v| {
|
} else if (cutPrefix(u8, arg, "--work-path=")) |v| {
|
||||||
work_path = v;
|
work_path = v;
|
||||||
|
} else if (cutPrefix(u8, arg, "--root-path=")) |v| {
|
||||||
|
root_path = v;
|
||||||
} else if (cutPrefix(u8, arg, "--only=")) |v| {
|
} else if (cutPrefix(u8, arg, "--only=")) |v| {
|
||||||
only_n = std.fmt.parseInt(usize, v, 10) catch {
|
only_n = std.fmt.parseInt(usize, v, 10) catch {
|
||||||
print("invalid --only value: {s}\n", .{v});
|
print("invalid --only value: {s}\n", .{v});
|
||||||
@@ -197,6 +222,7 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
.arena = arena,
|
.arena = arena,
|
||||||
.zig_exe = zig_exe,
|
.zig_exe = zig_exe,
|
||||||
.work_path = work_path,
|
.work_path = work_path,
|
||||||
|
.root_path = root_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@@ -238,7 +264,7 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// All solved.
|
// All solved.
|
||||||
print("{s}All exercises completed!{s}\n", .{ green_text, reset_text });
|
print("{s}All exercises completed!{s}\n", .{ C.green, C.reset });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
iterateFrom(ctx, start_index) catch std.process.exit(1);
|
iterateFrom(ctx, start_index) catch std.process.exit(1);
|
||||||
@@ -260,7 +286,7 @@ fn runOne(ctx: Context, ex: Exercise, mode: Mode) Error!void {
|
|||||||
if (ex.skip) {
|
if (ex.skip) {
|
||||||
print("Skipping {s}", .{ex.main_file});
|
print("Skipping {s}", .{ex.main_file});
|
||||||
if (ex.skip_hint) |hint|
|
if (ex.skip_hint) |hint|
|
||||||
print("\n{s}Reason: {s}{s}\n", .{ bold_text, hint, reset_text });
|
print("\n{s}Reason: {s}{s}\n", .{ C.bold, hint, C.reset });
|
||||||
print("\n\n", .{});
|
print("\n\n", .{});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -283,7 +309,7 @@ fn runOne(ctx: Context, ex: Exercise, mode: Mode) Error!void {
|
|||||||
|
|
||||||
fn hintAndHelp(ex: Exercise, mode: Mode) void {
|
fn hintAndHelp(ex: Exercise, mode: Mode) void {
|
||||||
if (ex.hint) |hint|
|
if (ex.hint) |hint|
|
||||||
print("\n{s}{s}Ziglings hint: {s}{s}", .{ bold_text, green_text, hint, reset_text });
|
print("\n{s}{s}Ziglings hint: {s}{s}", .{ C.bold, C.green, hint, C.reset });
|
||||||
help(ex, mode);
|
help(ex, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +336,7 @@ fn runExe(ctx: Context, ex: Exercise) !void {
|
|||||||
const arena = ctx.arena;
|
const arena = ctx.arena;
|
||||||
print("Compiling {s}...\n", .{ex.main_file});
|
print("Compiling {s}...\n", .{ex.main_file});
|
||||||
|
|
||||||
const path = std.fs.path.join(arena, &.{ ctx.work_path, ex.main_file }) catch @panic("OOM");
|
const path = std.fs.path.join(arena, &.{ ctx.root_path, ctx.work_path, ex.main_file }) catch @panic("OOM");
|
||||||
|
|
||||||
var argv = std.ArrayList([]const u8).initCapacity(arena, 8) catch @panic("OOM");
|
var argv = std.ArrayList([]const u8).initCapacity(arena, 8) catch @panic("OOM");
|
||||||
argv.append(arena, ctx.zig_exe) catch @panic("OOM");
|
argv.append(arena, ctx.zig_exe) catch @panic("OOM");
|
||||||
@@ -328,12 +354,11 @@ fn runExe(ctx: Context, ex: Exercise) !void {
|
|||||||
.stderr_limit = .limited(1024 * 1024),
|
.stderr_limit = .limited(1024 * 1024),
|
||||||
}) catch |err| {
|
}) catch |err| {
|
||||||
print("{s}error:{s} unable to run {s}: {s}\n", .{
|
print("{s}error:{s} unable to run {s}: {s}\n", .{
|
||||||
red_bold_text, reset_text, ex.main_file, @errorName(err),
|
C.red_bold, C.reset, ex.main_file, @errorName(err),
|
||||||
});
|
});
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
resetLine();
|
|
||||||
print("Checking {s}...\n", .{ex.main_file});
|
print("Checking {s}...\n", .{ex.main_file});
|
||||||
|
|
||||||
return checkOutput(io, arena, ex, result);
|
return checkOutput(io, arena, ex, result);
|
||||||
@@ -344,8 +369,7 @@ fn runTest(ctx: Context, ex: Exercise) !void {
|
|||||||
const arena = ctx.arena;
|
const arena = ctx.arena;
|
||||||
print("Compiling {s}...\n", .{ex.main_file});
|
print("Compiling {s}...\n", .{ex.main_file});
|
||||||
|
|
||||||
const path = std.fs.path.join(arena, &.{ ctx.work_path, ex.main_file }) catch
|
const path = std.fs.path.join(arena, &.{ ctx.root_path, ctx.work_path, ex.main_file }) catch @panic("OOM");
|
||||||
@panic("OOM");
|
|
||||||
|
|
||||||
var argv = std.ArrayList([]const u8).initCapacity(arena, 8) catch @panic("OOM");
|
var argv = std.ArrayList([]const u8).initCapacity(arena, 8) catch @panic("OOM");
|
||||||
argv.append(arena, ctx.zig_exe) catch @panic("OOM");
|
argv.append(arena, ctx.zig_exe) catch @panic("OOM");
|
||||||
@@ -362,12 +386,11 @@ fn runTest(ctx: Context, ex: Exercise) !void {
|
|||||||
.stderr_limit = .limited(1024 * 1024),
|
.stderr_limit = .limited(1024 * 1024),
|
||||||
}) catch |err| {
|
}) catch |err| {
|
||||||
print("{s}error:{s} unable to run test {s}: {s}\n", .{
|
print("{s}error:{s} unable to run test {s}: {s}\n", .{
|
||||||
red_bold_text, reset_text, ex.main_file, @errorName(err),
|
C.red_bold, C.reset, ex.main_file, @errorName(err),
|
||||||
});
|
});
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
resetLine();
|
|
||||||
print("Checking {s}...\n", .{ex.main_file});
|
print("Checking {s}...\n", .{ex.main_file});
|
||||||
|
|
||||||
return checkTest(ex, result);
|
return checkTest(ex, result);
|
||||||
@@ -384,7 +407,7 @@ fn checkOutput(io: std.Io, arena: std.mem.Allocator, ex: Exercise, result: Proce
|
|||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
print("{s}{s} terminated unexpectedly{s}\n", .{
|
print("{s}{s} terminated unexpectedly{s}\n", .{
|
||||||
red_bold_text, ex.main_file, reset_text,
|
C.red_bold, ex.main_file, C.reset,
|
||||||
});
|
});
|
||||||
return Error.Failed;
|
return Error.Failed;
|
||||||
},
|
},
|
||||||
@@ -419,8 +442,6 @@ fn checkOutput(io: std.Io, arena: std.mem.Allocator, ex: Exercise, result: Proce
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!std.mem.eql(u8, output, exercise_output)) {
|
if (!std.mem.eql(u8, output, exercise_output)) {
|
||||||
const red = red_bold_text;
|
|
||||||
const reset = reset_text;
|
|
||||||
print(
|
print(
|
||||||
\\
|
\\
|
||||||
\\{s}========= expected this output: =========={s}
|
\\{s}========= expected this output: =========={s}
|
||||||
@@ -428,11 +449,11 @@ fn checkOutput(io: std.Io, arena: std.mem.Allocator, ex: Exercise, result: Proce
|
|||||||
\\{s}========= but found: ====================={s}
|
\\{s}========= but found: ====================={s}
|
||||||
\\{s}
|
\\{s}
|
||||||
\\{s}=========================================={s}
|
\\{s}=========================================={s}
|
||||||
++ "\n", .{ red, reset, exercise_output, red, reset, output, red, reset });
|
++ "\n", .{ C.red_bold, C.reset, exercise_output, C.red_bold, C.reset, output, C.red_bold, C.reset });
|
||||||
return Error.Failed;
|
return Error.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
print("{s}PASSED:\n{s}{s}\n\n", .{ green_text, output, reset_text });
|
print("{s}PASSED:\n{s}{s}\n\n", .{ C.green, output, C.reset });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checkTest(ex: Exercise, result: Process.RunResult) !void {
|
fn checkTest(ex: Exercise, result: Process.RunResult) !void {
|
||||||
@@ -444,12 +465,12 @@ fn checkTest(ex: Exercise, result: Process.RunResult) !void {
|
|||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
print("{s}{s} terminated unexpectedly{s}\n", .{
|
print("{s}{s} terminated unexpectedly{s}\n", .{
|
||||||
red_bold_text, ex.main_file, reset_text,
|
C.red_bold, ex.main_file, C.reset,
|
||||||
});
|
});
|
||||||
return Error.Failed;
|
return Error.Failed;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
print("{s}PASSED{s}\n\n", .{ green_text, reset_text });
|
print("{s}PASSED{s}\n\n", .{ C.green, C.reset });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn help(ex: Exercise, mode: Mode) void {
|
fn help(ex: Exercise, mode: Mode) void {
|
||||||
@@ -459,14 +480,10 @@ fn help(ex: Exercise, mode: Mode) void {
|
|||||||
.random => "zig build -Drandom",
|
.random => "zig build -Drandom",
|
||||||
};
|
};
|
||||||
print("\n{s}Edit exercises/{s} and run '{s}' again.{s}\n", .{
|
print("\n{s}Edit exercises/{s} and run '{s}' again.{s}\n", .{
|
||||||
red_bold_text, ex.main_file, cmd, reset_text,
|
C.red_bold, ex.main_file, cmd, C.reset,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resetLine() void {
|
|
||||||
if (use_color_escapes) print("{s}", .{"\x1b[2K\r"});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes trailing whitespace per line and any trailing LF at the end.
|
// Removes trailing whitespace per line and any trailing LF at the end.
|
||||||
fn trimLines(arena: std.mem.Allocator, buf: []const u8) ![]const u8 {
|
fn trimLines(arena: std.mem.Allocator, buf: []const u8) ![]const u8 {
|
||||||
var list = try std.ArrayList(u8).initCapacity(arena, buf.len);
|
var list = try std.ArrayList(u8).initCapacity(arena, buf.len);
|
||||||
@@ -1150,7 +1167,7 @@ const exercises = [_]Exercise{
|
|||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "108_threading2.zig",
|
.main_file = "108_threading2.zig",
|
||||||
.output = "PI ≈ 3.14159265",
|
.output = "PI ≈ 3.14159265 (error = 1.0e-9)",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "109_files.zig",
|
.main_file = "109_files.zig",
|
||||||
|
|||||||
Reference in New Issue
Block a user