const std = @import("std"); const fs = std.fs; const FileRead = struct { file: fs.File, tasks: std.ArrayList([]const u8), }; pub fn readTasksFromFile(allocator: std.mem.Allocator, filename: []const u8) !FileRead { var tasks = std.ArrayList([]const u8).init(allocator); var file = fs.cwd().openFile(filename, .{ .mode = .read_write }) catch |err| { if (err == error.FileNotFound) { std.debug.print("File not found: {s}\n", .{filename}); const new_file = fs.cwd().createFile(filename, .{}) catch |e| { std.debug.print("Failed to create the file: {}", .{e}); return e; }; return FileRead{ .file = new_file, .tasks = tasks, }; } else { std.debug.print("Failed to open the file: {s}, error: {}\n", .{ filename, err }); return err; } }; // wrap the file reader in a buffered reader // since it's usually faster to read a bunch of bytes at once. var buf_reader = std.io.bufferedReader(file.reader()); const reader = buf_reader.reader(); var line = std.ArrayList(u8).init(allocator); defer line.deinit(); const writer = line.writer(); while (reader.streamUntilDelimiter(writer, '\n', null)) { // clear the line so we can reuse it defer line.clearRetainingCapacity(); const copy = try allocator.dupe(u8, line.items); try tasks.append(copy); } else |err| switch (err) { error.EndOfStream => { // end of file if (line.items.len > 0) { const copy = try allocator.dupe(u8, line.items); try tasks.append(copy); } }, else => return err, //propagate error } return FileRead{ .file = file, .tasks = tasks }; } pub fn writeTasksToFile(file_system: FileRead) !void { // truncate try file_system.file.setEndPos(0); // set cursor to 0 try file_system.file.seekTo(0); for (file_system.tasks.items) |item| { try file_system.file.writeAll(item); try file_system.file.writeAll("\n"); } }