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