Open directories of files

You can pass files / dirs as arguments an they will be opened. The
directories will be searched for text files (as identified by libmagic)
and those text files will be displayed too.
This commit is contained in:
Nathan McRae 2023-06-20 22:32:04 -07:00
parent 0da13751d5
commit 32c0b9bb5c
2 changed files with 330 additions and 280 deletions

View File

@ -7,6 +7,7 @@ pub fn build(b: *Builder) void {
exe.setBuildMode(mode); exe.setBuildMode(mode);
exe.linkSystemLibrary("SDL2"); exe.linkSystemLibrary("SDL2");
exe.linkSystemLibrary("SDL2_TTF"); exe.linkSystemLibrary("SDL2_TTF");
exe.linkSystemLibrary("magic");
exe.linkSystemLibrary("c"); exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step); b.default_step.dependOn(&exe.step);

View File

@ -1,280 +1,329 @@
const std = @import("std"); const std = @import("std");
const c = @cImport({ const c = @cImport({
@cInclude("SDL.h"); @cInclude("SDL.h");
@cInclude("SDL_ttf.h"); @cInclude("SDL_ttf.h");
}); });
const assert = @import("std").debug.assert; const m = @cImport({
@cInclude("magic.h");
const DrawnText = struct { });
surface: [*c]c.SDL_Surface,
texture: ?*c.SDL_Texture, const assert = @import("std").debug.assert;
rect: c.SDL_Rect,
}; const DrawnText = struct {
surface: [*c]c.SDL_Surface,
const FileDocMap = struct { texture: ?*c.SDL_Texture,
title_text: DrawnText, rect: c.SDL_Rect,
contents: []u8, };
};
const FileDocMap = struct {
pub fn main() !void { title_text: DrawnText,
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; contents: []u8,
defer { };
if(gpa.deinit()) {
std.debug.print("Allocator leak\n", .{}); pub fn main() !void {
} var gpa = std.heap.GeneralPurposeAllocator(.{}){};
} defer {
if (gpa.deinit()) {
const allocator = gpa.allocator(); std.debug.print("Allocator leak\n", .{});
}
const window_width = 300; }
const window_height = 500;
const column_width = 100; var magic = m.magic_open(m.MAGIC_MIME | m.MAGIC_CHECK);
const load_result = m.magic_load(magic, null);
if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0) { if (load_result != 0) {
c.SDL_Log("Unable to initialize SDL: %s", c.SDL_GetError()); std.debug.print("Unable to initialize magic: {d}", .{load_result});
return error.SDLInitializationFailed; return error.MagicInitializationFailed;
} }
defer c.SDL_Quit();
const allocator = gpa.allocator();
const screen = c.SDL_CreateWindow("Document Map Viewer", c.SDL_WINDOWPOS_UNDEFINED, c.SDL_WINDOWPOS_UNDEFINED, window_width, window_height, c.SDL_WINDOW_OPENGL) orelse
{ const args = try std.process.argsAlloc(allocator);
c.SDL_Log("Unable to create window: %s", c.SDL_GetError()); defer std.process.argsFree(allocator, args);
return error.SDLInitializationFailed;
}; const window_width = 700;
defer c.SDL_DestroyWindow(screen); const window_height = 500;
const column_width = 100;
const renderer = c.SDL_CreateRenderer(screen, -1, 0) orelse {
c.SDL_Log("Unable to create renderer: %s", c.SDL_GetError()); if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0) {
return error.SDLInitializationFailed; c.SDL_Log("Unable to initialize SDL: %s", c.SDL_GetError());
}; return error.SDLInitializationFailed;
defer c.SDL_DestroyRenderer(renderer); }
defer c.SDL_Quit();
// Turn on anti-aliasing
// :( doesn't seem to work const screen = c.SDL_CreateWindow("Document Map Viewer", c.SDL_WINDOWPOS_UNDEFINED, c.SDL_WINDOWPOS_UNDEFINED, window_width, window_height, c.SDL_WINDOW_OPENGL) orelse
const aa_result = c.SDL_SetHint(c.SDL_HINT_RENDER_SCALE_QUALITY, "1"); {
if (aa_result != c.SDL_TRUE) { c.SDL_Log("Unable to create window: %s", c.SDL_GetError());
c.SDL_Log("Unable to set anti-aliasing: %d", c.SDL_GetError()); return error.SDLInitializationFailed;
return error.SDLInitializationFailed; };
} defer c.SDL_DestroyWindow(screen);
// https://github.com/cirosantilli/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/ttf.c const renderer = c.SDL_CreateRenderer(screen, -1, 0) orelse {
const ttf_init_result: c_int = c.TTF_Init(); c.SDL_Log("Unable to create renderer: %s", c.SDL_GetError());
if (ttf_init_result != 0) { return error.SDLInitializationFailed;
c.SDL_Log("Unable to init TTF: %d", ttf_init_result); };
return error.TTFInitializationFailed; defer c.SDL_DestroyRenderer(renderer);
}
defer c.TTF_Quit(); // Turn on anti-aliasing
// :( doesn't seem to work
const text_color: c.SDL_Color = c.SDL_Color { const aa_result = c.SDL_SetHint(c.SDL_HINT_RENDER_SCALE_QUALITY, "1");
.r = 0, if (aa_result != c.SDL_TRUE) {
.g = 0, c.SDL_Log("Unable to set anti-aliasing: %d", c.SDL_GetError());
.b = 0, return error.SDLInitializationFailed;
.a = 255 }
};
// https://github.com/cirosantilli/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/ttf.c
// TODO: can we embed this file? const ttf_init_result: c_int = c.TTF_Init();
const font: ?*c.TTF_Font = c.TTF_OpenFont("FreeSans.ttf", 12); if (ttf_init_result != 0) {
if (font == null) { c.SDL_Log("Unable to init TTF: %d", ttf_init_result);
const err = c.TTF_GetError(); return error.TTFInitializationFailed;
c.SDL_Log("Unable to load font: %s", err); }
return error.TTFFontLoadFailed; defer c.TTF_Quit();
}
const text_color: c.SDL_Color = c.SDL_Color{ .r = 0, .g = 0, .b = 0, .a = 255 };
var file_paths = std.ArrayList([]const u8).init(allocator);
defer file_paths.deinit(); // TODO: can we embed this file?
try file_paths.append("src/main.zig"); const font: ?*c.TTF_Font = c.TTF_OpenFont("FreeSans.ttf", 12);
try file_paths.append("GapProbeScan.cs"); if (font == null) {
const err = c.TTF_GetError();
var file_docmaps = std.ArrayList(FileDocMap).init(allocator); c.SDL_Log("Unable to load font: %s", err);
defer file_docmaps.deinit(); return error.TTFFontLoadFailed;
}
for (file_paths.items) |path| {
const surface: [*c]c.SDL_Surface = c.TTF_RenderText_Solid(font, @ptrCast([*c]const u8, path), text_color); var file_paths = std.ArrayList([]const u8).init(allocator);
if (surface == null) { defer file_paths.deinit();
c.SDL_Log("Unable to render text"); defer {
return error.RenderTextFailed; for (file_paths.items) |item| {
} allocator.free(item);
}
const texture: ?*c.SDL_Texture = c.SDL_CreateTextureFromSurface(renderer, surface); }
if (texture == null) {
c.SDL_Log("Unable to create texture from surface"); var args_i: usize = 1;
return error.CreateTextureFailed; while (args_i < args.len) : (args_i += 1) {
} const arg = args[args_i];
if (std.fs.cwd().openIterableDir(arg, .{})) |iter_dir| {
var rect = c.SDL_Rect { std.debug.print("searching dir for files: '{s}'\n", .{arg});
.x = 0,
.y = 0, var iter = iter_dir.iterate();
.w = surface.*.w, while (try iter.next()) |entry| {
.h = surface.*.h, if (entry.kind == .File) {
}; const entry_path = try std.fmt.allocPrint(allocator, "{s}{c}{s}\x00", .{
arg,
const file = try std.fs.cwd().openFile(path, .{ }); std.fs.path.sep,
defer file.close(); entry.name,
});
const stat = try file.stat(); const magic_result = m.magic_file(magic, @ptrCast([*c]const u8, entry_path));
var buffer = try allocator.alloc(u8, stat.size); std.debug.print("'{s}': {s}\n", .{ entry.name, magic_result });
if (std.mem.eql(u8, magic_result[0..5], "text/")) {
const bytes_read = try file.readAll(buffer); try file_paths.append(entry_path[0..(entry_path.len - 1)]);
if (bytes_read != stat.size) { } else {
std.debug.print("bytes_read: {any}, stat.size: {any}\n", .{ allocator.free(entry_path);
bytes_read, }
stat.size, }
}); }
return error.FileReadError; } else |_| {
} if (std.fs.cwd().openFile(arg, .{})) |file| {
file.close();
var docmap = FileDocMap { std.debug.print("Will do docmap for: '{s}'\n", .{arg});
.title_text = DrawnText { var path = try allocator.alloc(u8, arg.len);
.surface = surface, std.mem.copy(u8, path, arg);
.texture = texture, try file_paths.append(path);
.rect = rect, } else |_| {
}, std.debug.print("Arg not file: '{s}'\n", .{arg});
.contents = buffer, }
}; }
}
try file_docmaps.append(docmap);
} var file_docmaps = std.ArrayList(FileDocMap).init(allocator);
defer { defer file_docmaps.deinit();
for (file_docmaps.items) |docmap| {
c.SDL_FreeSurface(docmap.title_text.surface); for (file_paths.items) |path| {
c.SDL_DestroyTexture(docmap.title_text.texture); const surface: [*c]c.SDL_Surface = c.TTF_RenderText_Solid(font, @ptrCast([*c]const u8, path), text_color);
allocator.free(docmap.contents); if (surface == null) {
} c.SDL_Log("Unable to render text");
} return error.RenderTextFailed;
}
const color_result: c_int = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
if (color_result != 0) { const texture: ?*c.SDL_Texture = c.SDL_CreateTextureFromSurface(renderer, surface);
c.SDL_Log("Unable to set draw color: %d", color_result); if (texture == null) {
return error.SDLInitializationFailed; c.SDL_Log("Unable to create texture from surface");
} return error.CreateTextureFailed;
}
// const surface = c.SDL_GetWindowSurface(screen);
var rect = c.SDL_Rect{
var quit = false; .x = 0,
while (!quit) { .y = 0,
var event: c.SDL_Event = undefined; .w = surface.*.w,
while (c.SDL_PollEvent(&event) != 0) { .h = surface.*.h,
switch (event.@"type") { };
c.SDL_QUIT => {
quit = true; std.debug.print("open file: {s}\n", .{path});
}, const file = try std.fs.cwd().openFile(path, .{});
else => {}, defer file.close();
}
} const stat = try file.stat();
var buffer = try allocator.alloc(u8, stat.size);
const initial_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
if (initial_color_result != 0) { const bytes_read = try file.readAll(buffer);
c.SDL_Log("Unable to set draw color: %d", initial_color_result); if (bytes_read != stat.size) {
return error.SDLInitializationFailed; std.debug.print("bytes_read: {any}, stat.size: {any}\n", .{
} bytes_read,
stat.size,
// Draw white background });
var x: c_int = 0; return error.FileReadError;
while (x < window_width) : (x += 1) { }
var y: c_int = 0;
while (y < window_height) : (y += 1) { var docmap = FileDocMap{
const draw_result = c.SDL_RenderDrawPoint(renderer, x, y); .title_text = DrawnText{
if (draw_result != 0) { .surface = surface,
c.SDL_Log("Unable to draw point: %d", draw_result); .texture = texture,
return error.SDLDrawingFailed; .rect = rect,
} },
} .contents = buffer,
} };
var i: usize = 0; try file_docmaps.append(docmap);
var column: c_int = 0; }
x = 0; defer {
var y: c_int = 0; for (file_docmaps.items) |docmap| {
c.SDL_FreeSurface(docmap.title_text.surface);
for (file_docmaps.items) |docmap| { c.SDL_DestroyTexture(docmap.title_text.texture);
i = 0; allocator.free(docmap.contents);
}
var rect = c.SDL_Rect { }
.x = x,
.y = y, const color_result: c_int = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
.w = docmap.title_text.surface.*.w, if (color_result != 0) {
.h = docmap.title_text.surface.*.h, c.SDL_Log("Unable to set draw color: %d", color_result);
}; return error.SDLInitializationFailed;
}
// Display text
if (c.SDL_RenderCopy(renderer, docmap.title_text.texture, null, &rect) != 0) { // const surface = c.SDL_GetWindowSurface(screen);
c.SDL_Log("Unable to render copy");
} var quit = false;
while (!quit) {
y += docmap.title_text.rect.h; var event: c.SDL_Event = undefined;
// white: false, black: true while (c.SDL_PollEvent(&event) != 0) {
var color: bool = false; switch (event.@"type") {
while (i < docmap.contents.len) : (i += 1) { c.SDL_QUIT => {
if (docmap.contents[i] == 10) { quit = true;
y += 1; },
if (y > window_height) { else => {},
y = 0; }
column += 1; }
// std.debug.print("Column: {any}, x: {any}\n", .{column, column*column_width});
} const initial_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
x = column * column_width; if (initial_color_result != 0) {
c.SDL_Log("Unable to set draw color: %d", initial_color_result);
continue; return error.SDLInitializationFailed;
} }
if (docmap.contents[i] == 32 and color) { // Draw white background
color = false; var x: c_int = 0;
const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); while (x < window_width) : (x += 1) {
if (white_color_result != 0) { var y: c_int = 0;
c.SDL_Log("Unable to set draw color: %d", white_color_result); while (y < window_height) : (y += 1) {
return error.SDLInitializationFailed; const draw_result = c.SDL_RenderDrawPoint(renderer, x, y);
} if (draw_result != 0) {
} else if (docmap.contents[i] != 32 and !color) { c.SDL_Log("Unable to draw point: %d", draw_result);
color = true; return error.SDLDrawingFailed;
const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); }
if (black_color_result != 0) { }
c.SDL_Log("Unable to set draw color: %d", black_color_result); }
return error.SDLInitializationFailed;
} var i: usize = 0;
} var column: c_int = 0;
x = 0;
if (x < (column + 1) * column_width) { var y: c_int = 0;
const draw_result = c.SDL_RenderDrawPoint(renderer, x, y);
if (draw_result != 0) { for (file_docmaps.items) |docmap| {
c.SDL_Log("Unable to draw point: %d", draw_result); i = 0;
return error.SDLDrawingFailed;
} var rect = c.SDL_Rect{
} else { .x = x,
const red_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); .y = y,
if (red_color_result != 0) { .w = docmap.title_text.surface.*.w,
c.SDL_Log("Unable to set draw color: %d", red_color_result); .h = docmap.title_text.surface.*.h,
return error.SDLInitializationFailed; };
}
// Display text
const draw_result = c.SDL_RenderDrawPoint(renderer, (column + 1) * column_width - 1, y); if (c.SDL_RenderCopy(renderer, docmap.title_text.texture, null, &rect) != 0) {
if (draw_result != 0) { c.SDL_Log("Unable to render copy");
c.SDL_Log("Unable to draw point: %d", draw_result); }
return error.SDLDrawingFailed;
} y += docmap.title_text.rect.h;
// white: false, black: true
if (!color) { var color: bool = false;
const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); while (i < docmap.contents.len) : (i += 1) {
if (white_color_result != 0) { if (docmap.contents[i] == 10) {
c.SDL_Log("Unable to set draw color: %d", white_color_result); y += 1;
return error.SDLInitializationFailed; if (y > window_height) {
} y = 0;
} else { column += 1;
const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // std.debug.print("Column: {any}, x: {any}\n", .{column, column*column_width});
if (black_color_result != 0) { }
c.SDL_Log("Unable to set draw color: %d", black_color_result); x = column * column_width;
return error.SDLInitializationFailed;
} continue;
} }
}
if (docmap.contents[i] == 32 and color) {
x += 1; color = false;
} const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
} if (white_color_result != 0) {
c.SDL_Log("Unable to set draw color: %d", white_color_result);
c.SDL_RenderPresent(renderer); return error.SDLInitializationFailed;
}
c.SDL_Delay(17); } else if (docmap.contents[i] != 32 and !color) {
} color = true;
} const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
if (black_color_result != 0) {
c.SDL_Log("Unable to set draw color: %d", black_color_result);
return error.SDLInitializationFailed;
}
}
if (x < (column + 1) * column_width) {
const draw_result = c.SDL_RenderDrawPoint(renderer, x, y);
if (draw_result != 0) {
c.SDL_Log("Unable to draw point: %d", draw_result);
return error.SDLDrawingFailed;
}
} else {
const red_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
if (red_color_result != 0) {
c.SDL_Log("Unable to set draw color: %d", red_color_result);
return error.SDLInitializationFailed;
}
const draw_result = c.SDL_RenderDrawPoint(renderer, (column + 1) * column_width - 1, y);
if (draw_result != 0) {
c.SDL_Log("Unable to draw point: %d", draw_result);
return error.SDLDrawingFailed;
}
if (!color) {
const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
if (white_color_result != 0) {
c.SDL_Log("Unable to set draw color: %d", white_color_result);
return error.SDLInitializationFailed;
}
} else {
const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
if (black_color_result != 0) {
c.SDL_Log("Unable to set draw color: %d", black_color_result);
return error.SDLInitializationFailed;
}
}
}
x += 1;
}
}
c.SDL_RenderPresent(renderer);
c.SDL_Delay(17);
}
}