~jamii/focus

bdd2f4c21951616751b3d05edea49ea427930445 — Jamie Brandon 1 year, 6 days ago d8f7705
Be careful not to recreate deleted files.
5 files changed, 57 insertions(+), 12 deletions(-)

M lib/focus.zig
M lib/focus/buffer.zig
M lib/focus/editor.zig
M lib/focus/file_opener.zig
M lib/focus/window.zig
M lib/focus.zig => lib/focus.zig +2 -0
@@ 250,6 250,8 @@ pub const App = struct {
            return buffer;
        } else {
            const buffer = Buffer.initFromAbsoluteFilename(self, .Real, absolute_filename);
            // buffer might be out of date if file was modified elsewhere
            buffer.refresh();
            self.buffers.put(self.dupe(absolute_filename), buffer) catch oom();
            return buffer;
        }

M lib/focus/buffer.zig => lib/focus/buffer.zig +38 -4
@@ 127,7 127,7 @@ pub const Buffer = struct {
        mtime: i128,
    };
    fn tryLoad(self: *Buffer) !TryLoadResult {
        const file = try std.fs.cwd().createFile(self.source.File.absolute_filename, .{ .read = true, .truncate = false });
        const file = try std.fs.cwd().openFile(self.source.File.absolute_filename, .{});
        defer file.close();

        const mtime = (try file.stat()).mtime;


@@ 165,7 165,16 @@ pub const Buffer = struct {
        switch (self.source) {
            .None => {},
            .File => |file_source| {
                const file = std.fs.cwd().createFile(file_source.absolute_filename, .{ .read = true, .truncate = false }) catch |err| panic("{} while refreshing {s}", .{ err, file_source.absolute_filename });
                const file = std.fs.cwd().openFile(file_source.absolute_filename, .{}) catch |err| {
                    switch (err) {
                        // if file has been deleted, leave buffer as is
                        error.FileNotFound => {
                            self.modified_since_last_save = true;
                            return;
                        },
                        else => panic("{} while refreshing {s}", .{ err, file_source.absolute_filename }),
                    }
                };
                defer file.close();
                const stat = file.stat() catch |err| panic("{} while refreshing {s}", .{ err, file_source.absolute_filename });
                if (stat.mtime != file_source.mtime) {


@@ 175,12 184,37 @@ pub const Buffer = struct {
        }
    }

    pub fn save(self: *Buffer) void {
    pub const SaveSource = enum {
        User,
        Auto,
    };
    pub fn save(self: *Buffer, source: SaveSource) void {
        switch (self.source) {
            .None => {},
            .File => |*file_source| {
                const file = std.fs.cwd().createFile(file_source.absolute_filename, .{ .read = false, .truncate = true }) catch |err| panic("{} while saving {s}", .{ err, file_source.absolute_filename });
                const file = switch (source) {
                    .User => std.fs.cwd().createFile(file_source.absolute_filename, .{ .read = false, .truncate = true }) catch |err| {
                        panic("{} while saving {s}", .{ err, file_source.absolute_filename });
                    },
                    .Auto => file: {
                        if (std.fs.cwd().openFile(file_source.absolute_filename, .{ .read = false, .write = true })) |file| {
                            file.setEndPos(0) catch |err| panic("{} while truncating {s}", .{ err, file_source.absolute_filename });
                            file.seekTo(0) catch |err| panic("{} while truncating {s}", .{ err, file_source.absolute_filename });
                            break :file file;
                        } else |err| {
                            switch (err) {
                                // if file has been deleted, only save in response to C-s
                                error.FileNotFound => {
                                    self.modified_since_last_save = true;
                                    return;
                                },
                                else => panic("{} while saving {s}", .{ err, file_source.absolute_filename }),
                            }
                        }
                    },
                };
                defer file.close();

                file.writeAll(self.bytes.items) catch |err| panic("{} while saving {s}", .{ err, file_source.absolute_filename });
                const stat = file.stat() catch |err| panic("{} while saving {s}", .{ err, file_source.absolute_filename });
                file_source.mtime = stat.mtime;

M lib/focus/editor.zig => lib/focus/editor.zig +3 -3
@@ 166,7 166,7 @@ pub const Editor = struct {
                                self.clearMark();
                            },
                            'd' => self.addNextMatch(),
                            's' => self.save(),
                            's' => self.save(.User),
                            'f' => {
                                const buffer_searcher = BufferSearcher.init(self.app, self);
                                window.pushView(buffer_searcher);


@@ 1027,10 1027,10 @@ pub const Editor = struct {
        }
    }

    pub fn save(self: *Editor) void {
    pub fn save(self: *Editor, source: Buffer.SaveSource) void {
        if (self.buffer.modified_since_last_save) {
            self.tryFormat();
            self.buffer.save();
            self.buffer.save(source);
        }
    }


M lib/focus/file_opener.zig => lib/focus/file_opener.zig +10 -1
@@ 104,9 104,18 @@ pub const FileOpener = struct {
                filename.appendSlice(results.items[self.selector.selected]) catch oom();
            }
            if (filename.items.len > 0 and std.fs.path.isSep(filename.items[filename.items.len - 1])) {
                // TODO mkdir?
                if (action == .SelectRaw)
                    std.fs.cwd().makeDir(filename.items) catch |err| {
                        panic("{} while creating directory {}", .{ err, filename });
                    };
                self.input.setText(filename.items);
            } else {
                if (action == .SelectRaw) {
                    const file = std.fs.cwd().createFile(filename.items, .{ .truncate = false }) catch |err| {
                        panic("{} while creating file {}", .{ err, filename });
                    };
                    file.close();
                }
                const new_buffer = self.app.getBufferFromAbsoluteFilename(filename.items);
                const new_editor = Editor.init(self.app, new_buffer, true, true);
                window.popView();

M lib/focus/window.zig => lib/focus/window.zig +4 -4
@@ 254,7 254,7 @@ pub const Window = struct {
                c.SDL_WINDOWEVENT => {
                    switch (event.window.event) {
                        c.SDL_WINDOWEVENT_FOCUS_LOST => {
                            if (self.getTopViewIfEditor()) |editor| editor.save();
                            if (self.getTopViewIfEditor()) |editor| editor.save(.Auto);
                            handled = true;
                        },
                        c.SDL_WINDOWEVENT_CLOSE => {


@@ 335,7 335,7 @@ pub const Window = struct {
        // clean up
        self.deinitPoppedViews();
        if (self.close_after_frame) {
            if (self.getTopViewIfEditor()) |editor| editor.save();
            if (self.getTopViewIfEditor()) |editor| editor.save(.Auto);
            if (self.client_address_o) |client_address|
                focus.sendReply(self.app.server_socket, client_address, 0);
            self.deinit();


@@ 391,7 391,7 @@ pub const Window = struct {
    // view api

    pub fn pushView(self: *Window, view_ptr: anytype) void {
        if (self.getTopViewIfEditor()) |editor| editor.save();
        if (self.getTopViewIfEditor()) |editor| editor.save(.Auto);
        const tag_name = @typeName(@typeInfo(@TypeOf(view_ptr)).Pointer.child);
        const view = @unionInit(View, tag_name, view_ptr);
        self.views.append(view) catch oom();


@@ 409,7 409,7 @@ pub const Window = struct {
        while (self.popped_views.items.len > 0) {
            const view = self.popped_views.pop();
            switch (view) {
                .Editor => |editor| editor.save(),
                .Editor => |editor| editor.save(.Auto),
                else => {},
            }
            inline for (@typeInfo(ViewTag).Enum.fields) |field| {