uf @ master

  1const std = @import("std");
  2const File = std.fs.File;
  3const Reader = std.fs.File.Reader;
  4const Writer = std.fs.File.Writer;
  5
  6pub fn main() !void {
  7    const in = std.io.getStdIn();
  8    const out = std.io.getStdOut();
  9    Uf.init().streamCopy(in.reader(), out.writer()) catch |err| {
 10        try std.io.getStdErr().writer().print("Error {}", .{err});
 11    };
 12}
 13
 14const buf_size = 1_000_000;
 15
 16const Uf = struct {
 17    const Self = @This();
 18
 19    var out_buf: [buf_size]u8 = undefined;
 20    var out_index: u32 = 0;
 21
 22    fn init() Self {
 23        return Self{};
 24    }
 25
 26    fn flush(_: Self, out: anytype) !void {
 27        _ = try out.write(out_buf[0..out_index]);
 28        out_index = 0;
 29    }
 30
 31    fn writeChar(self: Self, out: anytype, c: u8) !void {
 32        if (out_index >= buf_size) {
 33            try self.flush(out);
 34        }
 35        out_buf[out_index] = c;
 36        out_index += 1;
 37    }
 38
 39    fn streamCopy(self: Self, reader: anytype, writer: anytype) !void {
 40        var hit = false;
 41        var second = false;
 42        var in_buf: [buf_size]u8 = undefined;
 43        while (true) {
 44            const size = try reader.read(&in_buf);
 45
 46            for (in_buf[0..size]) |c| {
 47                if (hit and c == '\n') {
 48                    if (second == false) {
 49                        second = true;
 50                    } else {
 51                        continue;
 52                    }
 53                } else if (hit and c != '\n') {
 54                    if (second) {
 55                        try self.writeChar(writer, '\n');
 56                    } else {
 57                        try self.writeChar(writer, ' ');
 58                    }
 59                    hit = false;
 60                    second = false;
 61                } else if (c == '\n') {
 62                    hit = true;
 63                    continue;
 64                }
 65
 66                try self.writeChar(writer, c);
 67            }
 68
 69            if (size != in_buf.len) {
 70                try self.flush(writer);
 71                return;
 72            }
 73        }
 74    }
 75};
 76
 77test "Test format" {
 78    const text_in =
 79        \\# This is a markdown
 80        \\
 81        \\Lorem ipsum dolor sit amet,
 82        \\consectetur adipiscing elit.
 83        \\
 84        \\
 85        \\
 86        \\Praesent pharetra sit amet ante sit amet consequat.
 87    ;
 88
 89    const text_out =
 90        \\# This is a markdown
 91        \\
 92        \\Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 93        \\
 94        \\Praesent pharetra sit amet ante sit amet consequat.
 95    ;
 96
 97    var stream = std.io.fixedBufferStream(text_in);
 98
 99    var list = std.ArrayList(u8).init(std.testing.allocator);
100    defer list.deinit();
101
102    try Uf.init().streamCopy(stream.reader(), list.writer());
103    try std.testing.expect(std.mem.eql(u8, text_out, list.items));
104}