~subsetpark/erasmus

11f4cdc4e13f080db0e6aee6133fc6d7526c3c8d — Zach Smith 2 months ago 58b6093
Organize code a little
1 files changed, 101 insertions(+), 74 deletions(-)

M src/main.zig
M src/main.zig => src/main.zig +101 -74
@@ 29,9 29,20 @@ const EscapedString = struct {
    error_slice: ?[]const u8,
};

const CharBuffer = std.ArrayList(u8);

const help_text =
    \\Usage: er [-h] [-d] [DIRECTORY_NAME]
    \\
    \\  -h                Display this help message and quit.
    \\  -d                Enable debug mode.
    \\  DIRECTORY_NAME    Specify the directory `er` runs in. Defaults to ".".
    \\
;

// Read a note from disk, filtering out any lines
// inserted by the indexing process.
fn readBody(entry_name: []const u8, contents: *std.ArrayList(u8)) !void {
fn readBody(entry_name: []const u8, contents: *CharBuffer) !void {
    const file = try fs.cwd().openFile(entry_name, .{});
    defer file.close();



@@ 79,7 90,8 @@ fn readBody(entry_name: []const u8, contents: *std.ArrayList(u8)) !void {

// Iterate through a slice and populate an ArrayList with subslices capturing
// "{<reference>}"
fn findBracketedStrings(note_body: []const u8, brackets: *Brackets) !void {
fn findBracketedStrings(note_body: []const u8, brackets: *Brackets) !bool {
    var found = false;
    var i: usize = 0;
    var current_slice: ?usize = null;
    while (i < note_body.len) : (i += 1) {


@@ 97,6 109,7 @@ fn findBracketedStrings(note_body: []const u8, brackets: *Brackets) !void {
                if (i - slice_start > 1) {
                    // If we are closing an existing reference and the brackets
                    // aren't empty, push a new slice.
                    found = true;
                    try brackets.brackets.append(note_body[slice_start + 1 .. i]);
                }
                current_slice = null;


@@ 106,10 119,11 @@ fn findBracketedStrings(note_body: []const u8, brackets: *Brackets) !void {
            current_slice = null;
        }
    }
    return found;
}

// Create a reference line and add it to a note.
fn appendRef(note_body: *std.ArrayList(u8), referent: []const u8, allocator: *mem.Allocator) !void {
fn appendRef(note_body: *CharBuffer, referent: []const u8, allocator: *mem.Allocator) !void {
    const ref = try fmt.allocPrint(allocator, "{s}:{s}", .{
        ref_prefix,
        referent,


@@ 144,14 158,82 @@ fn escape(s: []const u8, res: *EscapedString) RuntimeError!void {
    }
}

const help_text =
    \\Usage: er [-h] [-d] [DIRECTORY_NAME]
    \\
    \\  -h                Display this help message and quit.
    \\  -d                Enable debug mode.
    \\  DIRECTORY_NAME    Specify the directory `er` runs in. Defaults to ".".
    \\
;
// Backlinks: if any other note body refers to this one, add a reference to
// that body's name.
fn appendBacklinks(
    note_name: []const u8,
    note_body: *CharBuffer,
    notes: std.StringHashMap(CharBuffer),
    allocator: *mem.Allocator,
) !void {
    var found_one = false;
    var all_notes = notes.iterator();

    const link_here = try fmt.allocPrint(allocator, "{c}{s}{c}", .{
        begin_brackets,
        note_name,
        end_brackets,
    });

    while (all_notes.next()) |entry| {
        const items = entry.value_ptr.*.items;
        if (mem.indexOf(u8, items, link_here) != null) {
            found_one = true;
            try appendRef(note_body, entry.key_ptr.*, allocator);
        }
    }

    // Backlinks padding.
    if (found_one) {
        try note_body.append('\n');
    }
}

// References: gather every reference in the body of the note.
fn appendReferences(
    note_name: []const u8,
    note_body: *CharBuffer,
    notes: std.StringHashMap(CharBuffer),
    allocator: *mem.Allocator,
) !void {
    var brackets = Brackets{
        .brackets = std.ArrayList([]const u8).init(allocator),
        .error_slice = undefined,
    };
    defer brackets.brackets.deinit();

    const found_one = findBracketedStrings(note_body.items, &brackets) catch |err| switch (err) {
        RuntimeError.BracketInBrackets => {
            std.debug.print("Found improperly nested brackets: {s}.\n", .{
                brackets.error_slice,
            });
            std.os.exit(1);
        },
        else => {
            return err;
        },
    };
    // References padding.
    if (found_one) {
        try note_body.append('\n');
    }
    // Escape and add forward references to note.
    for (brackets.brackets.items) |phrase| {
        var escaped = EscapedString{
            .escaped = try CharBuffer.initCapacity(allocator, phrase.len * 2),
            .error_slice = undefined,
        };
        defer escaped.escaped.deinit();

        escape(phrase, &escaped) catch |err| {
            std.debug.print("Found illegal character in brackets: `{s}`\n", .{
                escaped.error_slice,
            });
            std.os.exit(1);
        };
        try appendRef(note_body, escaped.escaped.items, allocator);
    }
}

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);


@@ 176,7 258,7 @@ pub fn main() !void {
    }
    const directory_name = maybe_directory_name orelse ".";

    var notes = std.StringHashMap(std.ArrayList(u8)).init(allocator);
    var notes = std.StringHashMap(CharBuffer).init(allocator);

    // Load note bodies into memory.
    const dir = try fs.cwd().openDir(directory_name, .{ .iterate = true });


@@ 187,13 269,13 @@ pub fn main() !void {
                directory_name,
                entry.name,
            });
            var contents = std.ArrayList(u8).init(allocator);
            var contents = CharBuffer.init(allocator);
            try readBody(path, &contents);
            try notes.put(entry.name, contents);
        }
    }

    var next_generation = std.StringHashMap(std.ArrayList(u8)).init(allocator);
    var next_generation = std.StringHashMap(CharBuffer).init(allocator);
    defer next_generation.deinit();

    // For each note, gather backlinks and references, and generate


@@ 201,69 283,14 @@ pub fn main() !void {
    var note_names = notes.keyIterator();
    while (note_names.next()) |note_name_ptr| {
        const note_name = note_name_ptr.*;
        const link_here = try fmt.allocPrint(allocator, "{c}{s}{c}", .{
            begin_brackets,
            note_name,
            end_brackets,
        });

        const maybe_note_body = notes.get(note_name);
        if (maybe_note_body) |note_body| {
            var new_note_body = std.ArrayList(u8).init(allocator);
            // Backlinks: if any other note body refers to this one, add a
            // reference to that body's name.
            var found_a_backlink = false;
            var all_notes = notes.iterator();
            while (all_notes.next()) |entry| {
                const items = entry.value_ptr.*.items;
                if (mem.indexOf(u8, items, link_here) != null) {
                    found_a_backlink = true;
                    try appendRef(&new_note_body, entry.key_ptr.*, allocator);
                }
            }
            // Backlinks padding.
            if (found_a_backlink) {
                try new_note_body.append('\n');
            }
            // Body: Add main note body.
            var new_note_body = CharBuffer.init(allocator);

            try appendBacklinks(note_name, &new_note_body, notes, allocator);
            try new_note_body.appendSlice(note_body.items);
            // References: gather every reference in the body of the note.
            var brackets = Brackets{
                .brackets = std.ArrayList([]const u8).init(allocator),
                .error_slice = undefined,
            };
            defer brackets.brackets.deinit();
            findBracketedStrings(note_body.items, &brackets) catch |err| switch (err) {
                RuntimeError.BracketInBrackets => {
                    std.debug.print("Found improperly nested brackets: {s}.\n", .{
                        brackets.error_slice,
                    });
                    std.os.exit(1);
                },
                else => {
                    return err;
                },
            };
            // References padding.
            if (brackets.brackets.items.len > 0) {
                try new_note_body.append('\n');
            }
            // References: escape and add forward references to note.
            for (brackets.brackets.items) |phrase| {
                var escaped = EscapedString{
                    .escaped = try std.ArrayList(u8).initCapacity(allocator, phrase.len * 2),
                    .error_slice = undefined,
                };
                defer escaped.escaped.deinit();

                escape(phrase, &escaped) catch |err| {
                    std.debug.print("Found illegal character in brackets: `{s}`\n", .{
                        escaped.error_slice,
                    });
                    std.os.exit(1);
                };
                try appendRef(&new_note_body, escaped.escaped.items, allocator);
            }
            try appendReferences(note_name, &new_note_body, notes, allocator);

            // Optional debugging.
            if (debug_mode) {
                std.debug.print("{s}:\n\n{s}\n", .{