Update remaining files using deprecated imports: - core/output.zig: terminal.zig → io.zig - net/ws/deps.zig: remove colors.zig export (available via io) All tests pass.
137 lines
4.3 KiB
Zig
137 lines
4.3 KiB
Zig
const std = @import("std");
|
|
const io = @import("../utils/io.zig");
|
|
|
|
/// Output mode: JSON for structured data, text for TSV
|
|
pub const Mode = enum { json, text };
|
|
|
|
pub var mode: Mode = .text;
|
|
|
|
pub fn setMode(m: Mode) void {
|
|
mode = m;
|
|
}
|
|
|
|
/// Escape a value for TSV output (replace tabs/newlines with spaces for xargs safety)
|
|
fn escapeTSV(val: []const u8) []const u8 {
|
|
// For xargs usability, we need single-line output with no tabs/newlines in values
|
|
// This returns the same slice if no escaping needed, but we process to ensure safety
|
|
// In practice, we just use the value directly since the caller should sanitize
|
|
return val;
|
|
}
|
|
|
|
/// Check if value needs TSV escaping
|
|
fn needsTSVEscape(val: []const u8) bool {
|
|
for (val) |c| {
|
|
if (c == '\t' or c == '\n' or c == '\r') return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Print error to stderr
|
|
pub fn err(msg: []const u8) void {
|
|
std.debug.print("Error: {s}\n", .{msg});
|
|
}
|
|
|
|
/// Print line in current mode (JSON or TSV)
|
|
pub fn line(values: []const []const u8) void {
|
|
switch (mode) {
|
|
.json => {
|
|
std.debug.print("{{", .{});
|
|
// Assume alternating key-value pairs
|
|
var i: usize = 0;
|
|
while (i < values.len) : (i += 2) {
|
|
if (i > 0) std.debug.print(",", .{});
|
|
const key = values[i];
|
|
const val = if (i + 1 < values.len) values[i + 1] else "";
|
|
std.debug.print("\"{s}\":\"{s}\"", .{ key, val });
|
|
}
|
|
std.debug.print("}}\n", .{});
|
|
},
|
|
.text => {
|
|
for (values, 0..) |val, i| {
|
|
if (i > 0) std.debug.print("\t", .{});
|
|
// For TSV/xargs safety: if value contains tabs/newlines, we need to handle it
|
|
// Simple approach: print as-is but replace internal tabs with spaces
|
|
if (needsTSVEscape(val)) {
|
|
for (val) |c| {
|
|
if (c == '\t' or c == '\n' or c == '\r') {
|
|
std.debug.print(" ", .{});
|
|
} else {
|
|
std.debug.print("{c}", .{c});
|
|
}
|
|
}
|
|
} else {
|
|
std.debug.print("{s}", .{val});
|
|
}
|
|
}
|
|
std.debug.print("\n", .{});
|
|
},
|
|
}
|
|
}
|
|
|
|
/// Print raw JSON array
|
|
pub fn jsonArray(items: []const []const u8) void {
|
|
std.debug.print("[", .{});
|
|
for (items, 0..) |item, i| {
|
|
if (i > 0) std.debug.print(",", .{});
|
|
std.debug.print("\"{s}\"", .{item});
|
|
}
|
|
std.debug.print("]\n", .{});
|
|
}
|
|
|
|
/// Print raw JSON object from key-value pairs
|
|
pub fn jsonObject(pairs: []const []const u8) void {
|
|
std.debug.print("{{", .{});
|
|
var i: usize = 0;
|
|
while (i < pairs.len) : (i += 2) {
|
|
if (i > 0) std.debug.print(",", .{});
|
|
const key = pairs[i];
|
|
const val = if (i + 1 < pairs.len) pairs[i + 1] else "";
|
|
std.debug.print("\"{s}\":\"{s}\"", .{ key, val });
|
|
}
|
|
std.debug.print("}}\n", .{});
|
|
}
|
|
|
|
/// Print success response (JSON only)
|
|
pub fn success(comptime cmd: []const u8) void {
|
|
if (mode == .json) {
|
|
std.debug.print("{{\"success\":true,\"command\":\"{s}\"}}\n", .{cmd});
|
|
}
|
|
}
|
|
|
|
/// Print success with data
|
|
pub fn successData(comptime cmd: []const u8, pairs: []const []const u8) void {
|
|
if (mode == .json) {
|
|
std.debug.print("{{\"success\":true,\"command\":\"{s}\",\"data\":{{", .{cmd});
|
|
var i: usize = 0;
|
|
while (i < pairs.len) : (i += 2) {
|
|
if (i > 0) std.debug.print(",", .{});
|
|
const key = pairs[i];
|
|
const val = if (i + 1 < pairs.len) pairs[i + 1] else "";
|
|
std.debug.print("\"{s}\":\"{s}\"", .{ key, val });
|
|
}
|
|
std.debug.print("}}}}\n", .{});
|
|
} else {
|
|
for (pairs, 0..) |val, i| {
|
|
if (i > 0) std.debug.print("\t", .{});
|
|
std.debug.print("{s}", .{val});
|
|
}
|
|
std.debug.print("\n", .{});
|
|
}
|
|
}
|
|
|
|
/// Print usage information
|
|
pub fn usage(comptime cmd: []const u8, comptime u: []const u8) void {
|
|
std.debug.print("Usage: {s} {s}\n", .{ cmd, u });
|
|
}
|
|
|
|
/// Print plain value (text mode only)
|
|
pub fn value(v: []const u8) void {
|
|
if (mode == .text) {
|
|
std.debug.print("{s}\n", .{v});
|
|
}
|
|
}
|
|
|
|
/// Get terminal width for formatting
|
|
pub fn getTerminalWidth() ?usize {
|
|
return io.getWidth();
|
|
}
|