mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00
Merge pull request #85 from jetzig-framework/routes-command
Add `jetzig routes` command
This commit is contained in:
commit
aafcd4cddc
21
build.zig
21
build.zig
@ -155,7 +155,7 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn
|
|||||||
&[_][]const u8{ root_path, "src", "app", "mailers" },
|
&[_][]const u8{ root_path, "src", "app", "mailers" },
|
||||||
);
|
);
|
||||||
|
|
||||||
var generate_routes = try Routes.init(
|
var routes = try Routes.init(
|
||||||
b.allocator,
|
b.allocator,
|
||||||
root_path,
|
root_path,
|
||||||
templates_path,
|
templates_path,
|
||||||
@ -163,11 +163,11 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn
|
|||||||
jobs_path,
|
jobs_path,
|
||||||
mailers_path,
|
mailers_path,
|
||||||
);
|
);
|
||||||
try generate_routes.generateRoutes();
|
const generated_routes = try routes.generateRoutes();
|
||||||
const routes_write_files = b.addWriteFiles();
|
const routes_write_files = b.addWriteFiles();
|
||||||
const routes_file = routes_write_files.add("routes.zig", generate_routes.buffer.items);
|
const routes_file = routes_write_files.add("routes.zig", generated_routes);
|
||||||
const tests_write_files = b.addWriteFiles();
|
const tests_write_files = b.addWriteFiles();
|
||||||
const tests_file = tests_write_files.add("tests.zig", generate_routes.buffer.items);
|
const tests_file = tests_write_files.add("tests.zig", generated_routes);
|
||||||
const routes_module = b.createModule(.{ .root_source_file = routes_file });
|
const routes_module = b.createModule(.{ .root_source_file = routes_file });
|
||||||
|
|
||||||
var src_dir = try std.fs.openDirAbsolute(b.pathFromRoot("src"), .{ .iterate = true });
|
var src_dir = try std.fs.openDirAbsolute(b.pathFromRoot("src"), .{ .iterate = true });
|
||||||
@ -229,6 +229,19 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn
|
|||||||
test_step.dependOn(&run_exe_unit_tests.step);
|
test_step.dependOn(&run_exe_unit_tests.step);
|
||||||
test_step.dependOn(&run_static_routes_cmd.step);
|
test_step.dependOn(&run_static_routes_cmd.step);
|
||||||
exe_unit_tests.root_module.addImport("routes", routes_module);
|
exe_unit_tests.root_module.addImport("routes", routes_module);
|
||||||
|
|
||||||
|
const routes_step = b.step("jetzig:routes", "List all routes in your app");
|
||||||
|
const exe_routes = b.addExecutable(.{
|
||||||
|
.name = "routes",
|
||||||
|
.root_source_file = jetzig_dep.path("src/routes.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
exe_routes.root_module.addImport("jetzig", jetzig_module);
|
||||||
|
exe_routes.root_module.addImport("routes", routes_module);
|
||||||
|
exe_routes.root_module.addImport("app", &exe.root_module);
|
||||||
|
const run_routes_cmd = b.addRunArtifact(exe_routes);
|
||||||
|
routes_step.dependOn(&run_routes_cmd.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generateMarkdownFragments(b: *std.Build) ![]const u8 {
|
fn generateMarkdownFragments(b: *std.Build) ![]const u8 {
|
||||||
|
12
cli/cli.zig
12
cli/cli.zig
@ -4,6 +4,7 @@ const init = @import("commands/init.zig");
|
|||||||
const update = @import("commands/update.zig");
|
const update = @import("commands/update.zig");
|
||||||
const generate = @import("commands/generate.zig");
|
const generate = @import("commands/generate.zig");
|
||||||
const server = @import("commands/server.zig");
|
const server = @import("commands/server.zig");
|
||||||
|
const routes = @import("commands/routes.zig");
|
||||||
const bundle = @import("commands/bundle.zig");
|
const bundle = @import("commands/bundle.zig");
|
||||||
const tests = @import("commands/tests.zig");
|
const tests = @import("commands/tests.zig");
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ const Options = struct {
|
|||||||
.update = "Update current project to latest version of Jetzig",
|
.update = "Update current project to latest version of Jetzig",
|
||||||
.generate = "Generate scaffolding",
|
.generate = "Generate scaffolding",
|
||||||
.server = "Run a development server",
|
.server = "Run a development server",
|
||||||
|
.routes = "List all routes in your app",
|
||||||
.bundle = "Create a deployment bundle",
|
.bundle = "Create a deployment bundle",
|
||||||
.@"test" = "Run app tests",
|
.@"test" = "Run app tests",
|
||||||
.help = "Print help and exit",
|
.help = "Print help and exit",
|
||||||
@ -33,10 +35,12 @@ const Verb = union(enum) {
|
|||||||
update: update.Options,
|
update: update.Options,
|
||||||
generate: generate.Options,
|
generate: generate.Options,
|
||||||
server: server.Options,
|
server: server.Options,
|
||||||
|
routes: routes.Options,
|
||||||
bundle: bundle.Options,
|
bundle: bundle.Options,
|
||||||
@"test": tests.Options,
|
@"test": tests.Options,
|
||||||
g: generate.Options,
|
g: generate.Options,
|
||||||
s: server.Options,
|
s: server.Options,
|
||||||
|
r: routes.Options,
|
||||||
b: bundle.Options,
|
b: bundle.Options,
|
||||||
t: tests.Options,
|
t: tests.Options,
|
||||||
};
|
};
|
||||||
@ -70,6 +74,7 @@ pub fn main() !void {
|
|||||||
\\ update Update current project to latest version of Jetzig.
|
\\ update Update current project to latest version of Jetzig.
|
||||||
\\ generate Generate scaffolding.
|
\\ generate Generate scaffolding.
|
||||||
\\ server Run a development server.
|
\\ server Run a development server.
|
||||||
|
\\ routes List all routes in your app.
|
||||||
\\ bundle Create a deployment bundle.
|
\\ bundle Create a deployment bundle.
|
||||||
\\ test Run app tests.
|
\\ test Run app tests.
|
||||||
\\
|
\\
|
||||||
@ -110,6 +115,13 @@ fn run(allocator: std.mem.Allocator, options: args.ParseArgsResult(Options, Verb
|
|||||||
options.positionals,
|
options.positionals,
|
||||||
.{ .help = options.options.help },
|
.{ .help = options.options.help },
|
||||||
),
|
),
|
||||||
|
.r, .routes => |opts| routes.run(
|
||||||
|
allocator,
|
||||||
|
opts,
|
||||||
|
writer,
|
||||||
|
options.positionals,
|
||||||
|
.{ .help = options.options.help },
|
||||||
|
),
|
||||||
.b, .bundle => |opts| bundle.run(
|
.b, .bundle => |opts| bundle.run(
|
||||||
allocator,
|
allocator,
|
||||||
opts,
|
opts,
|
||||||
|
45
cli/commands/routes.zig
Normal file
45
cli/commands/routes.zig
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const args = @import("args");
|
||||||
|
const util = @import("../util.zig");
|
||||||
|
|
||||||
|
/// Command line options for the `routes` command.
|
||||||
|
pub const Options = struct {
|
||||||
|
pub const meta = .{
|
||||||
|
.usage_summary = "",
|
||||||
|
.full_text =
|
||||||
|
\\Output all available routes for this app.
|
||||||
|
\\
|
||||||
|
\\Example:
|
||||||
|
\\
|
||||||
|
\\ jetzig routes
|
||||||
|
,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Run the `jetzig routes` command.
|
||||||
|
pub fn run(
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
options: Options,
|
||||||
|
writer: anytype,
|
||||||
|
positionals: [][]const u8,
|
||||||
|
other_options: struct { help: bool },
|
||||||
|
) !void {
|
||||||
|
_ = positionals;
|
||||||
|
_ = options;
|
||||||
|
if (other_options.help) {
|
||||||
|
try args.printHelp(Options, "jetzig routes", writer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cwd = try util.detectJetzigProjectDir();
|
||||||
|
defer cwd.close();
|
||||||
|
|
||||||
|
const realpath = try std.fs.realpathAlloc(allocator, ".");
|
||||||
|
defer allocator.free(realpath);
|
||||||
|
|
||||||
|
try util.runCommandStreaming(allocator, realpath, &[_][]const u8{
|
||||||
|
"zig",
|
||||||
|
"build",
|
||||||
|
"jetzig:routes",
|
||||||
|
});
|
||||||
|
}
|
@ -175,16 +175,18 @@ pub const jetzig_options = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn init(app: *jetzig.App) !void {
|
||||||
|
// Example custom route:
|
||||||
|
app.route(.GET, "/custom/:id/foo/bar", @import("app/views/custom/foo.zig"), .bar);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.c_allocator;
|
const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.c_allocator;
|
||||||
defer if (builtin.mode == .Debug) std.debug.assert(gpa.deinit() == .ok);
|
defer if (builtin.mode == .Debug) std.debug.assert(gpa.deinit() == .ok);
|
||||||
|
|
||||||
const app = try jetzig.init(allocator);
|
var app = try jetzig.init(allocator);
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
|
||||||
// Example custom route:
|
|
||||||
// app.route(.GET, "/custom/:id/foo/bar", @import("app/views/custom/foo.zig"), .bar);
|
|
||||||
|
|
||||||
try app.start(routes, .{});
|
try app.start(routes, .{});
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ pub fn deinit(self: *Routes) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates the complete route set for the application
|
/// Generates the complete route set for the application
|
||||||
pub fn generateRoutes(self: *Routes) !void {
|
pub fn generateRoutes(self: *Routes) ![]const u8 {
|
||||||
const writer = self.buffer.writer();
|
const writer = self.buffer.writer();
|
||||||
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
@ -177,6 +177,7 @@ pub fn generateRoutes(self: *Routes) !void {
|
|||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return try self.buffer.toOwnedSlice();
|
||||||
// std.debug.print("routes.zig\n{s}\n", .{self.buffer.items});
|
// std.debug.print("routes.zig\n{s}\n", .{self.buffer.items});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +271,7 @@ fn writeRoute(self: *Routes, writer: std.ArrayList(u8).Writer, route: Function)
|
|||||||
\\ .action = .{1s},
|
\\ .action = .{1s},
|
||||||
\\ .view_name = "{2s}",
|
\\ .view_name = "{2s}",
|
||||||
\\ .view = jetzig.Route.ViewType{{ .{3s} = .{{ .{1s} = @import("{7s}").{1s} }} }},
|
\\ .view = jetzig.Route.ViewType{{ .{3s} = .{{ .{1s} = @import("{7s}").{1s} }} }},
|
||||||
|
\\ .path = "{7s}",
|
||||||
\\ .static = {4s},
|
\\ .static = {4s},
|
||||||
\\ .uri_path = "{5s}",
|
\\ .uri_path = "{5s}",
|
||||||
\\ .template = "{6s}",
|
\\ .template = "{6s}",
|
||||||
|
@ -209,6 +209,8 @@ pub const config = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const initHook: ?*const fn (*App) anyerror!void = if (@hasDecl(root, "init")) root.init else null;
|
||||||
|
|
||||||
/// Initialize a new Jetzig app. Call this from `src/main.zig` and then call
|
/// Initialize a new Jetzig app. Call this from `src/main.zig` and then call
|
||||||
/// `start(@import("routes").routes)` on the returned value.
|
/// `start(@import("routes").routes)` on the returned value.
|
||||||
pub fn init(allocator: std.mem.Allocator) !App {
|
pub fn init(allocator: std.mem.Allocator) !App {
|
||||||
@ -221,5 +223,6 @@ pub fn init(allocator: std.mem.Allocator) !App {
|
|||||||
.environment = environment,
|
.environment = environment,
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.custom_routes = std.ArrayList(views.Route).init(allocator),
|
.custom_routes = std.ArrayList(views.Route).init(allocator),
|
||||||
|
.initHook = initHook,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ const App = @This();
|
|||||||
environment: jetzig.Environment,
|
environment: jetzig.Environment,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
custom_routes: std.ArrayList(jetzig.views.Route),
|
custom_routes: std.ArrayList(jetzig.views.Route),
|
||||||
|
initHook: ?*const fn (*App) anyerror!void,
|
||||||
|
|
||||||
pub fn deinit(self: *const App) void {
|
pub fn deinit(self: *const App) void {
|
||||||
@constCast(self).custom_routes.deinit();
|
@constCast(self).custom_routes.deinit();
|
||||||
@ -22,9 +23,11 @@ const AppOptions = struct {};
|
|||||||
/// Starts an application. `routes` should be `@import("routes").routes`, a generated file
|
/// Starts an application. `routes` should be `@import("routes").routes`, a generated file
|
||||||
/// automatically created at build time. `templates` should be
|
/// automatically created at build time. `templates` should be
|
||||||
/// `@import("src/app/views/zmpl.manifest.zig").templates`, created by Zmpl at compile time.
|
/// `@import("src/app/views/zmpl.manifest.zig").templates`, created by Zmpl at compile time.
|
||||||
pub fn start(self: App, routes_module: type, options: AppOptions) !void {
|
pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||||
_ = options; // See `AppOptions`
|
_ = options; // See `AppOptions`
|
||||||
|
|
||||||
|
if (self.initHook) |hook| try hook(@constCast(self));
|
||||||
|
|
||||||
var mime_map = jetzig.http.mime.MimeMap.init(self.allocator);
|
var mime_map = jetzig.http.mime.MimeMap.init(self.allocator);
|
||||||
defer mime_map.deinit();
|
defer mime_map.deinit();
|
||||||
try mime_map.build();
|
try mime_map.build();
|
||||||
@ -137,7 +140,7 @@ pub fn start(self: App, routes_module: type, options: AppOptions) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn route(
|
pub fn route(
|
||||||
self: *const App,
|
self: *App,
|
||||||
comptime method: jetzig.http.Request.Method,
|
comptime method: jetzig.http.Request.Method,
|
||||||
comptime path: []const u8,
|
comptime path: []const u8,
|
||||||
comptime module: type,
|
comptime module: type,
|
||||||
@ -155,11 +158,11 @@ pub fn route(
|
|||||||
@memcpy(&view_name, module_name);
|
@memcpy(&view_name, module_name);
|
||||||
std.mem.replaceScalar(u8, &view_name, '.', '/');
|
std.mem.replaceScalar(u8, &view_name, '.', '/');
|
||||||
|
|
||||||
@constCast(self).custom_routes.append(.{
|
self.custom_routes.append(.{
|
||||||
.name = member,
|
.name = member,
|
||||||
.action = .custom,
|
.action = .custom,
|
||||||
.method = method,
|
.method = method,
|
||||||
.view_name = self.allocator.dupe(u8, &view_name) catch @panic("OOM"),
|
.view_name = module_name,
|
||||||
.uri_path = path,
|
.uri_path = path,
|
||||||
.layout = if (@hasDecl(module, "layout")) module.layout else null,
|
.layout = if (@hasDecl(module, "layout")) module.layout else null,
|
||||||
.view = comptime switch (viewType(path)) {
|
.view = comptime switch (viewType(path)) {
|
||||||
|
@ -119,6 +119,10 @@ fn runtimeWrap(allocator: std.mem.Allocator, attribute: []const u8, message: []c
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bold(comptime message: []const u8) []const u8 {
|
||||||
|
return codes.escape ++ codes.bold ++ message ++ codes.escape ++ codes.reset;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn black(comptime message: []const u8) []const u8 {
|
pub fn black(comptime message: []const u8) []const u8 {
|
||||||
return wrap(codes.black, message);
|
return wrap(codes.black, message);
|
||||||
}
|
}
|
||||||
|
@ -170,23 +170,26 @@ pub const Reader = struct {
|
|||||||
self.queue.writer.mutex.lock();
|
self.queue.writer.mutex.lock();
|
||||||
defer self.queue.writer.mutex.unlock();
|
defer self.queue.writer.mutex.unlock();
|
||||||
|
|
||||||
const writer = switch (event.target) {
|
switch (event.target) {
|
||||||
.stdout => blk: {
|
.stdout => {
|
||||||
stdout_written = true;
|
stdout_written = true;
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
file = self.stdout_file;
|
file = self.stdout_file;
|
||||||
colorize = self.queue.stdout_colorize;
|
colorize = self.queue.stdout_colorize;
|
||||||
}
|
}
|
||||||
break :blk stdout_writer;
|
|
||||||
},
|
},
|
||||||
.stderr => blk: {
|
.stderr => {
|
||||||
stderr_written = true;
|
stderr_written = true;
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
file = self.stderr_file;
|
file = self.stderr_file;
|
||||||
colorize = self.queue.stderr_colorize;
|
colorize = self.queue.stderr_colorize;
|
||||||
}
|
}
|
||||||
break :blk stderr_writer;
|
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const writer = switch (event.target) {
|
||||||
|
.stdout => stdout_writer,
|
||||||
|
.stderr => stderr_writer,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (event.ptr) |ptr| {
|
if (event.ptr) |ptr| {
|
||||||
@ -196,11 +199,7 @@ pub const Reader = struct {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builtin.os.tag == .windows and colorize) {
|
try jetzig.util.writeAnsi(file, writer, event.message[0..event.len]);
|
||||||
try writeWindows(file, writer, event);
|
|
||||||
} else {
|
|
||||||
try writer.writeAll(event.message[0..event.len]);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.queue.writer.position -= 1;
|
self.queue.writer.position -= 1;
|
||||||
|
|
||||||
@ -273,20 +272,14 @@ fn initPool(allocator: std.mem.Allocator, T: type) std.heap.MemoryPool(T) {
|
|||||||
|
|
||||||
fn writeWindows(file: std.fs.File, writer: anytype, event: Event) !void {
|
fn writeWindows(file: std.fs.File, writer: anytype, event: Event) !void {
|
||||||
var info: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
|
var info: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
|
||||||
_ = std.os.windows.kernel32.GetConsoleScreenBufferInfo(
|
_ = std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info);
|
||||||
file.handle,
|
|
||||||
&info
|
|
||||||
);
|
|
||||||
|
|
||||||
var it = std.mem.tokenizeSequence(u8, event.message[0..event.len], "\x1b[");
|
var it = std.mem.tokenizeSequence(u8, event.message[0..event.len], "\x1b[");
|
||||||
while (it.next()) |token| {
|
while (it.next()) |token| {
|
||||||
if (std.mem.indexOfScalar(u8, token, 'm')) |index| {
|
if (std.mem.indexOfScalar(u8, token, 'm')) |index| {
|
||||||
if (index > 0 and index + 1 < token.len) {
|
if (index > 0 and index + 1 < token.len) {
|
||||||
if (jetzig.colors.windows_map.get(token[0..index])) |color| {
|
if (jetzig.colors.windows_map.get(token[0..index])) |color| {
|
||||||
try std.os.windows.SetConsoleTextAttribute(
|
try std.os.windows.SetConsoleTextAttribute(file.handle, color);
|
||||||
file.handle,
|
|
||||||
color
|
|
||||||
);
|
|
||||||
try writer.writeAll(token[index + 1 ..]);
|
try writer.writeAll(token[index + 1 ..]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ store: *jetzig.kv.Store,
|
|||||||
cache: *jetzig.kv.Store,
|
cache: *jetzig.kv.Store,
|
||||||
job_queue: *jetzig.kv.Store,
|
job_queue: *jetzig.kv.Store,
|
||||||
|
|
||||||
|
const initHook = jetzig.root.initHook;
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, routes_module: type) !App {
|
pub fn init(allocator: std.mem.Allocator, routes_module: type) !App {
|
||||||
switch (jetzig.testing.state) {
|
switch (jetzig.testing.state) {
|
||||||
.ready => {},
|
.ready => {},
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
const colors = @import("colors.zig");
|
||||||
|
|
||||||
/// Compare two strings with case-insensitive matching.
|
/// Compare two strings with case-insensitive matching.
|
||||||
pub fn equalStringsCaseInsensitive(expected: []const u8, actual: []const u8) bool {
|
pub fn equalStringsCaseInsensitive(expected: []const u8, actual: []const u8) bool {
|
||||||
@ -85,3 +88,30 @@ pub fn generateVariableName(buf: *[32]u8) []const u8 {
|
|||||||
}
|
}
|
||||||
return buf[0..32];
|
return buf[0..32];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write a string of bytes, possibly containing ANSI escape codes. Translate ANSI escape codes
|
||||||
|
/// into Windows API console commands. Allow building an ANSI string and writing at once to a
|
||||||
|
/// Windows console. In non-Windows environments, output ANSI bytes directly.
|
||||||
|
pub fn writeAnsi(file: std.fs.File, writer: anytype, text: []const u8) !void {
|
||||||
|
if (builtin.os.tag != .windows) {
|
||||||
|
try writer.writeAll(text);
|
||||||
|
} else {
|
||||||
|
var info: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
|
||||||
|
_ = std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info);
|
||||||
|
|
||||||
|
var it = std.mem.tokenizeSequence(u8, text, "\x1b[");
|
||||||
|
while (it.next()) |token| {
|
||||||
|
if (std.mem.indexOfScalar(u8, token, 'm')) |index| {
|
||||||
|
if (index > 0 and index + 1 < token.len) {
|
||||||
|
if (colors.windows_map.get(token[0..index])) |color| {
|
||||||
|
try std.os.windows.SetConsoleTextAttribute(file.handle, color);
|
||||||
|
try writer.writeAll(token[index + 1 ..]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback
|
||||||
|
try writer.writeAll(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -51,6 +51,7 @@ action: Action,
|
|||||||
method: jetzig.http.Request.Method = undefined, // Used by custom routes only
|
method: jetzig.http.Request.Method = undefined, // Used by custom routes only
|
||||||
view_name: []const u8,
|
view_name: []const u8,
|
||||||
uri_path: []const u8,
|
uri_path: []const u8,
|
||||||
|
path: ?[]const u8 = null,
|
||||||
view: ViewType,
|
view: ViewType,
|
||||||
render: RenderFn = renderFn,
|
render: RenderFn = renderFn,
|
||||||
renderStatic: RenderStaticFn = renderStaticFn,
|
renderStatic: RenderStaticFn = renderStaticFn,
|
||||||
|
69
src/routes.zig
Normal file
69
src/routes.zig
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const routes = @import("routes");
|
||||||
|
const app = @import("app");
|
||||||
|
const jetzig = @import("jetzig");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
comptime var max_uri_path_len: usize = 0;
|
||||||
|
|
||||||
|
log("Jetzig Routes:", .{});
|
||||||
|
|
||||||
|
const environment = jetzig.Environment.init(undefined);
|
||||||
|
const initHook: ?*const fn (*jetzig.App) anyerror!void = if (@hasDecl(app, "init")) app.init else null;
|
||||||
|
|
||||||
|
inline for (routes.routes) |route| max_uri_path_len = @max(route.uri_path.len + 5, max_uri_path_len);
|
||||||
|
const padded_path = std.fmt.comptimePrint("{{s: <{}}}", .{max_uri_path_len});
|
||||||
|
|
||||||
|
inline for (routes.routes) |route| {
|
||||||
|
const action = comptime switch (route.action) {
|
||||||
|
.get => jetzig.colors.cyan("{s: <7}"),
|
||||||
|
.index => jetzig.colors.blue("{s: <7}"),
|
||||||
|
.post => jetzig.colors.yellow("{s: <7}"),
|
||||||
|
.put => jetzig.colors.magenta("{s: <7}"),
|
||||||
|
.patch => jetzig.colors.purple("{s: <7}"),
|
||||||
|
.delete => jetzig.colors.red("{s: <7}"),
|
||||||
|
.custom => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
log(" " ++ action ++ " " ++ padded_path ++ " {?s}", .{
|
||||||
|
@tagName(route.action),
|
||||||
|
route.uri_path ++ switch (route.action) {
|
||||||
|
.index, .post => "",
|
||||||
|
.get, .put, .patch, .delete => "/:id",
|
||||||
|
.custom => "",
|
||||||
|
},
|
||||||
|
route.path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var jetzig_app = jetzig.App{
|
||||||
|
.environment = environment,
|
||||||
|
.allocator = allocator,
|
||||||
|
.custom_routes = std.ArrayList(jetzig.views.Route).init(allocator),
|
||||||
|
.initHook = initHook,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (initHook) |hook| try hook(&jetzig_app);
|
||||||
|
|
||||||
|
for (jetzig_app.custom_routes.items) |route| {
|
||||||
|
log(
|
||||||
|
" " ++ jetzig.colors.bold(jetzig.colors.white("{s: <7}")) ++ " " ++ padded_path ++ " {s}:{s}",
|
||||||
|
.{ route.name, route.uri_path, route.view_name, route.name },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(comptime message: []const u8, args: anytype) void {
|
||||||
|
std.debug.print(message ++ "\n", args);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sortedRoutes(comptime unordered_routes: []const jetzig.views.Route) void {
|
||||||
|
comptime std.sort.pdq(jetzig.views.Route, unordered_routes, {}, lessThanFn);
|
||||||
|
}
|
||||||
|
pub fn lessThanFn(context: void, lhs: jetzig.views.Route, rhs: jetzig.views.Route) bool {
|
||||||
|
_ = context;
|
||||||
|
return std.mem.order(u8, lhs.uri_path, rhs.uri_path).compare(std.math.CompareOperator.lt);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user