From 8150e4665117768a45117e213353776cab5909a1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Jan 2026 01:09:55 +0000 Subject: [PATCH] Add colorful terminal UI styling to CLI tools Introduce ANSI color support for the hemlock interpreter and hemlockc compiler to provide a more polished and user-friendly terminal experience: - Create terminal.h with ANSI color macros and TTY detection - Add sexy ASCII art tree logo to REPL header - Colorize help text with section headers, options, and examples - Add colored error messages (red "error:" prefix) - Add progress indicators in compiler verbose mode ([1/5], [2/5], etc.) - Style file info output with highlighted values and formats - Color the REPL prompt (green ">>>") - Auto-detect color support (honors NO_COLOR, checks TERM and isatty) --- include/terminal.h | 198 ++++++++++++++++++++++++ src/backends/compiler/main.c | 92 ++++++----- src/backends/interpreter/main.c | 266 ++++++++++++++++++-------------- 3 files changed, 394 insertions(+), 162 deletions(-) create mode 100644 include/terminal.h diff --git a/include/terminal.h b/include/terminal.h new file mode 100644 index 00000000..47bce439 --- /dev/null +++ b/include/terminal.h @@ -0,0 +1,198 @@ +/* + * terminal.h - ANSI Terminal Colors and Styling + * + * Provides macros for colorful terminal output in Hemlock CLI tools. + * These are compile-time strings that can be concatenated with other strings. + */ + +#ifndef HEMLOCK_TERMINAL_H +#define HEMLOCK_TERMINAL_H + +#include +#include +#include + +// ========== ANSI ESCAPE CODES ========== + +// Reset all attributes +#define TERM_RESET "\033[0m" + +// Text styles +#define TERM_BOLD "\033[1m" +#define TERM_DIM "\033[2m" +#define TERM_ITALIC "\033[3m" +#define TERM_UNDERLINE "\033[4m" +#define TERM_BLINK "\033[5m" +#define TERM_REVERSE "\033[7m" + +// Regular colors (foreground) +#define TERM_BLACK "\033[30m" +#define TERM_RED "\033[31m" +#define TERM_GREEN "\033[32m" +#define TERM_YELLOW "\033[33m" +#define TERM_BLUE "\033[34m" +#define TERM_MAGENTA "\033[35m" +#define TERM_CYAN "\033[36m" +#define TERM_WHITE "\033[37m" + +// Bright colors (foreground) +#define TERM_GRAY "\033[90m" +#define TERM_BRIGHT_RED "\033[91m" +#define TERM_BRIGHT_GREEN "\033[92m" +#define TERM_BRIGHT_YELLOW "\033[93m" +#define TERM_BRIGHT_BLUE "\033[94m" +#define TERM_BRIGHT_MAGENTA "\033[95m" +#define TERM_BRIGHT_CYAN "\033[96m" +#define TERM_BRIGHT_WHITE "\033[97m" + +// Background colors +#define TERM_BG_BLACK "\033[40m" +#define TERM_BG_RED "\033[41m" +#define TERM_BG_GREEN "\033[42m" +#define TERM_BG_YELLOW "\033[43m" +#define TERM_BG_BLUE "\033[44m" +#define TERM_BG_MAGENTA "\033[45m" +#define TERM_BG_CYAN "\033[46m" +#define TERM_BG_WHITE "\033[47m" + +// Bright background colors +#define TERM_BG_GRAY "\033[100m" +#define TERM_BG_BRIGHT_RED "\033[101m" +#define TERM_BG_BRIGHT_GREEN "\033[102m" +#define TERM_BG_BRIGHT_YELLOW "\033[103m" +#define TERM_BG_BRIGHT_BLUE "\033[104m" +#define TERM_BG_BRIGHT_MAGENTA "\033[105m" +#define TERM_BG_BRIGHT_CYAN "\033[106m" +#define TERM_BG_BRIGHT_WHITE "\033[107m" + +// ========== SEMANTIC COLORS ========== + +// For success messages +#define TERM_SUCCESS TERM_BRIGHT_GREEN +// For error messages +#define TERM_ERROR TERM_BRIGHT_RED +// For warnings +#define TERM_WARNING TERM_BRIGHT_YELLOW +// For info/hints +#define TERM_INFO TERM_BRIGHT_CYAN +// For code/paths +#define TERM_CODE TERM_BRIGHT_WHITE +// For dimmed text +#define TERM_MUTED TERM_GRAY + +// ========== HEMLOCK BRAND COLORS ========== + +// Primary brand color (forest green - hemlock is a tree!) +#define TERM_HEMLOCK "\033[38;5;28m" +// Secondary brand color (darker green) +#define TERM_HEMLOCK_DARK "\033[38;5;22m" +// Accent color (gold/amber) +#define TERM_ACCENT "\033[38;5;214m" + +// ========== COLOR DETECTION ========== + +// Check if stdout supports color output +static inline int term_supports_color(void) { + // If not a TTY, no color + if (!isatty(STDOUT_FILENO)) { + return 0; + } + + // Check NO_COLOR environment variable (standard) + if (getenv("NO_COLOR") != NULL) { + return 0; + } + + // Check TERM environment variable + const char *term = getenv("TERM"); + if (term == NULL) { + return 0; + } + + // "dumb" terminal has no color support + if (strcmp(term, "dumb") == 0) { + return 0; + } + + // Most modern terminals support color + return 1; +} + +// Global color enable flag (set once at startup) +static int _term_color_enabled = -1; // -1 = uninitialized + +static inline int term_color_enabled(void) { + if (_term_color_enabled < 0) { + _term_color_enabled = term_supports_color(); + } + return _term_color_enabled; +} + +// Force color on/off (for --color/--no-color flags) +static inline void term_set_color(int enabled) { + _term_color_enabled = enabled; +} + +// ========== CONDITIONAL COLOR MACROS ========== + +// These return the color code only if colors are enabled +#define TERM_C(code) (term_color_enabled() ? (code) : "") + +// Convenience wrappers +#define C_RESET TERM_C(TERM_RESET) +#define C_BOLD TERM_C(TERM_BOLD) +#define C_DIM TERM_C(TERM_DIM) +#define C_RED TERM_C(TERM_RED) +#define C_GREEN TERM_C(TERM_GREEN) +#define C_YELLOW TERM_C(TERM_YELLOW) +#define C_BLUE TERM_C(TERM_BLUE) +#define C_MAGENTA TERM_C(TERM_MAGENTA) +#define C_CYAN TERM_C(TERM_CYAN) +#define C_WHITE TERM_C(TERM_WHITE) +#define C_GRAY TERM_C(TERM_GRAY) +#define C_SUCCESS TERM_C(TERM_SUCCESS) +#define C_ERROR TERM_C(TERM_ERROR) +#define C_WARNING TERM_C(TERM_WARNING) +#define C_INFO TERM_C(TERM_INFO) +#define C_CODE TERM_C(TERM_CODE) +#define C_MUTED TERM_C(TERM_MUTED) +#define C_HEMLOCK TERM_C(TERM_HEMLOCK) +#define C_ACCENT TERM_C(TERM_ACCENT) +#define C_UNDERLINE TERM_C(TERM_UNDERLINE) + +// ========== ASCII ART LOGO ========== + +// Small hemlock logo (fits in terminal nicely) +#define HEMLOCK_LOGO_SMALL \ + " /\\\n" \ + " / \\\n" \ + " /____\\\n" \ + " ||\n" + +// Medium hemlock tree logo +#define HEMLOCK_LOGO \ + " *\n" \ + " /|\\\n" \ + " / | \\\n" \ + " / | \\\n" \ + " / | \\\n" \ + " /_______\\\n" \ + " |||\n" \ + " |||\n" + +// Stylized text banner +#define HEMLOCK_BANNER \ + " _ _ _ _ \n" \ + "| | | | ___ _ __ ___ | | ___ ___| | __\n" \ + "| |_| |/ _ \\ '_ ` _ \\| |/ _ \\ / __| |/ /\n" \ + "| _ | __/ | | | | | | (_) | (__| < \n" \ + "|_| |_|\\___|_| |_| |_|_|\\___/ \\___|_|\\_\\\n" + +// Compact text banner +#define HEMLOCK_BANNER_COMPACT \ + " _ _ _ _ \n" \ + "| || |___ _ __ | |___ __| |__\n" \ + "| __ / -_) ' \\| / _ \\/ _| / /\n" \ + "|_||_\\___|_|_|_|_\\___/\\__|_\\_\\\n" + +#endif // HEMLOCK_TERMINAL_H diff --git a/src/backends/compiler/main.c b/src/backends/compiler/main.c index b7f63b28..7da447a0 100644 --- a/src/backends/compiler/main.c +++ b/src/backends/compiler/main.c @@ -14,6 +14,7 @@ #include "frontend.h" #include "../../include/version.h" #include "../../include/hemlock_limits.h" +#include "../../include/terminal.h" #include "codegen.h" #include "compiler/type_check.h" @@ -221,30 +222,37 @@ typedef struct { } Options; static void print_usage(const char *progname) { - fprintf(stderr, "Hemlock Compiler v%s\n\n", HEMLOCK_VERSION); - fprintf(stderr, "Usage: %s [options] \n\n", progname); - fprintf(stderr, "Options:\n"); - fprintf(stderr, " -o Output executable name (default: a.out)\n"); - fprintf(stderr, " -c Emit C code only (don't compile)\n"); - fprintf(stderr, " --emit-c Write generated C to file\n"); - fprintf(stderr, " -k, --keep-c Keep generated C file after compilation\n"); - fprintf(stderr, " -O Optimization level (0-3, default: 3)\n"); + // Header + fprintf(stderr, "%s%sHemlockc%s %s- Hemlock Compiler%s v%s%s%s\n\n", + C_BOLD, C_GREEN, C_RESET, C_MUTED, C_RESET, C_ACCENT, HEMLOCK_VERSION, C_RESET); + + // Usage + fprintf(stderr, "%s%sUSAGE%s\n", C_BOLD, C_YELLOW, C_RESET); + fprintf(stderr, " %s%s%s [options] \n\n", C_CODE, progname, C_RESET); + + // Options + fprintf(stderr, "%s%sOPTIONS%s\n", C_BOLD, C_YELLOW, C_RESET); + fprintf(stderr, " %s-o%s Output executable name (default: a.out)\n", C_CYAN, C_RESET); + fprintf(stderr, " %s-c%s Emit C code only (don't compile)\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--emit-c%s Write generated C to file\n", C_CYAN, C_RESET); + fprintf(stderr, " %s-k, --keep-c%s Keep generated C file after compilation\n", C_CYAN, C_RESET); + fprintf(stderr, " %s-O%s Optimization level (0-3, default: 3)\n", C_CYAN, C_RESET); #ifdef __APPLE__ - fprintf(stderr, " --cc C compiler to use (default: clang)\n"); + fprintf(stderr, " %s--cc%s C compiler to use (default: clang)\n", C_CYAN, C_RESET); #else - fprintf(stderr, " --cc C compiler to use (default: gcc)\n"); + fprintf(stderr, " %s--cc%s C compiler to use (default: gcc)\n", C_CYAN, C_RESET); #endif - fprintf(stderr, " --runtime

Path to runtime library\n"); - fprintf(stderr, " --check Type check only, don't compile\n"); - fprintf(stderr, " --no-type-check Disable type checking (less safe, fewer optimizations)\n"); - fprintf(stderr, " --strict-types Strict type checking (warn on implicit any)\n"); - fprintf(stderr, " --no-stack-check Disable stack overflow checking (faster, but no protection)\n"); - fprintf(stderr, " --static Static link all libraries (standalone binary)\n"); - fprintf(stderr, " --sandbox [DIR] Enable sandbox mode (restrict FFI, network, process, file writes)\n"); - fprintf(stderr, " If DIR provided, restricts file reads to that directory\n"); - fprintf(stderr, " -v, --verbose Verbose output\n"); - fprintf(stderr, " -h, --help Show this help message\n"); - fprintf(stderr, " --version Show version\n"); + fprintf(stderr, " %s--runtime%s

Path to runtime library\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--check%s Type check only, don't compile\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--no-type-check%s Disable type checking (less safe, fewer optimizations)\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--strict-types%s Strict type checking (warn on implicit any)\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--no-stack-check%s Disable stack overflow checking (faster, but no protection)\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--static%s Static link all libraries (standalone binary)\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--sandbox%s [DIR] Enable sandbox mode (restrict FFI, network, process, file writes)\n", C_CYAN, C_RESET); + fprintf(stderr, " %sIf DIR provided, restricts file reads to that directory%s\n", C_MUTED, C_RESET); + fprintf(stderr, " %s-v, --verbose%s Verbose output\n", C_CYAN, C_RESET); + fprintf(stderr, " %s-h, --help%s Show this help message\n", C_CYAN, C_RESET); + fprintf(stderr, " %s--version%s Show version\n", C_CYAN, C_RESET); } static Options parse_args(int argc, char **argv) { @@ -584,7 +592,7 @@ int main(int argc, char **argv) { // Parse if (opts.verbose) { - printf("Parsing %s...\n", opts.input_file); + printf("%s[1/5]%s Parsing %s%s%s...\n", C_MUTED, C_RESET, C_CODE, opts.input_file, C_RESET); } Lexer lexer; @@ -597,34 +605,34 @@ int main(int argc, char **argv) { Stmt **statements = parse_program(&parser, &stmt_count); if (parser.had_error) { - fprintf(stderr, "Parse failed!\n"); + fprintf(stderr, "%serror:%s Parse failed!\n", C_ERROR, C_RESET); free(source); return 1; } if (opts.verbose) { - printf("Parsed %d statements\n", stmt_count); + printf(" %sParsed %d statements%s\n", C_MUTED, stmt_count, C_RESET); } // Resolve variables (compute depth/slot indices - shared with interpreter) if (opts.verbose) { - printf("Resolving variables...\n"); + printf("%s[2/5]%s Resolving variables...\n", C_MUTED, C_RESET); } resolve_program(statements, stmt_count); // Optimize AST (constant folding, boolean simplification, strength reduction) // This runs before type checking to simplify patterns for analysis if (opts.verbose) { - printf("Optimizing AST...\n"); + printf("%s[3/5]%s Optimizing AST...\n", C_MUTED, C_RESET); } OptimizationStats opt_stats = optimize_program(statements, stmt_count); if (opts.verbose && (opt_stats.constants_folded > 0 || opt_stats.literals_folded > 0 || opt_stats.booleans_simplified > 0 || opt_stats.strength_reductions > 0 || opt_stats.dead_code_eliminated > 0)) { - printf(" Folded %d constants (%d literals), simplified %d booleans, %d strength reductions, %d dead-code eliminations\n", - opt_stats.constants_folded, opt_stats.literals_folded, + printf(" %sFolded %d constants (%d literals), simplified %d booleans, %d strength reductions, %d dead-code eliminations%s\n", + C_MUTED, opt_stats.constants_folded, opt_stats.literals_folded, opt_stats.booleans_simplified, opt_stats.strength_reductions, - opt_stats.dead_code_eliminated); + opt_stats.dead_code_eliminated, C_RESET); } // Type check (if enabled - on by default) @@ -632,7 +640,7 @@ int main(int argc, char **argv) { TypeCheckContext *type_ctx = NULL; if (opts.type_check) { if (opts.verbose) { - printf("Type checking...\n"); + printf("%s[4/5]%s Type checking...\n", C_MUTED, C_RESET); } type_ctx = type_check_new(opts.input_file); @@ -640,8 +648,8 @@ int main(int argc, char **argv) { int type_errors = type_check_program(type_ctx, statements, stmt_count); if (type_errors > 0) { - fprintf(stderr, "%d type error%s found\n", - type_errors, type_errors > 1 ? "s" : ""); + fprintf(stderr, "%serror:%s %d type error%s found\n", + C_ERROR, C_RESET, type_errors, type_errors > 1 ? "s" : ""); type_check_free(type_ctx); for (int i = 0; i < stmt_count; i++) { stmt_free(statements[i]); @@ -652,13 +660,13 @@ int main(int argc, char **argv) { } if (opts.verbose) { - printf("Type checking passed\n"); + printf(" %s%sType checking passed%s\n", C_SUCCESS, C_BOLD, C_RESET); } // If --check flag was used, exit after type checking if (opts.check_only) { if (!opts.verbose) { - printf("%s: no type errors\n", opts.input_file); + printf("%s%s%s: %sno type errors%s\n", C_CODE, opts.input_file, C_RESET, C_SUCCESS, C_RESET); } type_check_free(type_ctx); for (int i = 0; i < stmt_count; i++) { @@ -698,7 +706,7 @@ int main(int argc, char **argv) { // Open output file FILE *output = fopen(c_file, "w"); if (!output) { - fprintf(stderr, "Error: Could not open output file '%s'\n", c_file); + fprintf(stderr, "%serror:%s Could not open output file '%s'\n", C_ERROR, C_RESET, c_file); free(source); if (c_file_allocated) free(c_file); return 1; @@ -706,7 +714,7 @@ int main(int argc, char **argv) { // Generate C code if (opts.verbose) { - printf("Generating C code to %s...\n", c_file); + printf("%s[5/5]%s Generating C code to %s%s%s...\n", C_MUTED, C_RESET, C_CODE, c_file, C_RESET); } // Initialize module cache for import support @@ -737,7 +745,7 @@ int main(int argc, char **argv) { // Check for compilation errors int had_errors = ctx->error_count > 0; if (had_errors) { - fprintf(stderr, "%d error%s generated\n", ctx->error_count, ctx->error_count > 1 ? "s" : ""); + fprintf(stderr, "%serror:%s %d error%s generated\n", C_ERROR, C_RESET, ctx->error_count, ctx->error_count > 1 ? "s" : ""); } codegen_free(ctx); @@ -768,7 +776,7 @@ int main(int argc, char **argv) { if (opts.emit_c_only) { if (opts.verbose) { - printf("C code written to %s\n", c_file); + printf("%s%sC code written to %s%s\n", C_SUCCESS, C_BOLD, c_file, C_RESET); } if (c_file_allocated) free(c_file); return 0; @@ -776,7 +784,7 @@ int main(int argc, char **argv) { // Compile C code if (opts.verbose) { - printf("Compiling C code...\n"); + printf(" Compiling C code...\n"); } int result = compile_c(&opts, c_file); @@ -784,7 +792,7 @@ int main(int argc, char **argv) { // Cleanup temp file if (!opts.keep_c && !opts.c_output) { if (opts.verbose) { - printf("Removing temporary file %s\n", c_file); + printf(" %sRemoving temporary file %s%s\n", C_MUTED, c_file, C_RESET); } unlink(c_file); } @@ -793,10 +801,10 @@ int main(int argc, char **argv) { if (result == 0) { if (opts.verbose) { - printf("Successfully compiled to %s\n", opts.output_file); + printf("\n%s%sSuccessfully compiled to %s%s\n", C_SUCCESS, C_BOLD, opts.output_file, C_RESET); } } else { - fprintf(stderr, "C compilation failed with status %d\n", result); + fprintf(stderr, "%serror:%s C compilation failed with status %d\n", C_ERROR, C_RESET, result); } return result; diff --git a/src/backends/interpreter/main.c b/src/backends/interpreter/main.c index 73093dfa..7d31d924 100644 --- a/src/backends/interpreter/main.c +++ b/src/backends/interpreter/main.c @@ -11,6 +11,7 @@ #include "tools/bundler/bundler.h" #include "version.h" #include "profiler/profiler.h" +#include "terminal.h" #define HEMLOCK_BUILD_DATE __DATE__ #define HEMLOCK_BUILD_TIME __TIME__ @@ -27,7 +28,7 @@ extern void ffi_cleanup(void); static char* read_file(const char *path) { FILE *file = fopen(path, "rb"); if (file == NULL) { - fprintf(stderr, "Error: Could not open file '%s'\n", path); + fprintf(stderr, "%serror:%s Could not open file '%s'\n", C_ERROR, C_RESET, path); return NULL; } @@ -35,23 +36,23 @@ static char* read_file(const char *path) { fseek(file, 0, SEEK_END); long size = ftell(file); if (fseek(file, 0, SEEK_SET) != 0) { - fprintf(stderr, "Error: Could not seek to beginning of file\n"); + fprintf(stderr, "%serror:%s Could not seek to beginning of file\n", C_ERROR, C_RESET); fclose(file); return NULL; } - + // Allocate buffer char *buffer = malloc(size + 1); if (buffer == NULL) { - fprintf(stderr, "Error: Could not allocate memory for file\n"); + fprintf(stderr, "%serror:%s Could not allocate memory for file\n", C_ERROR, C_RESET); fclose(file); return NULL; } - + // Read file size_t bytes_read = fread(buffer, 1, size, file); if (bytes_read < (size_t)size) { - fprintf(stderr, "Error: Could not read file\n"); + fprintf(stderr, "%serror:%s Could not read file\n", C_ERROR, C_RESET); free(buffer); fclose(file); return NULL; @@ -195,7 +196,7 @@ static uint8_t* check_embedded_payload(size_t *out_size) { // Run an embedded payload (HMLB compressed or HMLC uncompressed) static int run_embedded_payload(uint8_t *payload, size_t payload_size, int argc, char **argv) { if (payload_size < 4) { - fprintf(stderr, "Error: Invalid embedded payload\n"); + fprintf(stderr, "%serror:%s Invalid embedded payload\n", C_ERROR, C_RESET); return 1; } @@ -206,7 +207,7 @@ static int run_embedded_payload(uint8_t *payload, size_t payload_size, int argc, if (magic == 0x424C4D48) { // "HMLB" (compressed) // Payload is in HMLB format: [magic:4][version:2][orig_size:4][compressed_data] if (payload_size < 10) { - fprintf(stderr, "Error: Invalid HMLB payload\n"); + fprintf(stderr, "%serror:%s Invalid HMLB payload\n", C_ERROR, C_RESET); return 1; } @@ -220,14 +221,14 @@ static int run_embedded_payload(uint8_t *payload, size_t payload_size, int argc, // Decompress uint8_t *decompressed = malloc(orig_size); if (!decompressed) { - fprintf(stderr, "Error: Cannot allocate memory for decompression\n"); + fprintf(stderr, "%serror:%s Cannot allocate memory for decompression\n", C_ERROR, C_RESET); return 1; } uLongf dest_len = orig_size; int ret = uncompress(decompressed, &dest_len, compressed_data, compressed_size); if (ret != Z_OK) { - fprintf(stderr, "Error: Decompression failed (%d)\n", ret); + fprintf(stderr, "%serror:%s Decompression failed (%d)\n", C_ERROR, C_RESET, ret); free(decompressed); return 1; } @@ -239,12 +240,12 @@ static int run_embedded_payload(uint8_t *payload, size_t payload_size, int argc, // Payload is already in HMLC format, deserialize directly statements = ast_deserialize(payload, payload_size, &stmt_count); } else { - fprintf(stderr, "Error: Unknown embedded payload format (magic: 0x%08x)\n", magic); + fprintf(stderr, "%serror:%s Unknown embedded payload format (magic: 0x%08x)\n", C_ERROR, C_RESET, magic); return 1; } if (!statements) { - fprintf(stderr, "Error: Failed to deserialize embedded code\n"); + fprintf(stderr, "%serror:%s Failed to deserialize embedded code\n", C_ERROR, C_RESET); return 1; } @@ -445,7 +446,7 @@ static int compile_file(const char *input_path, const char *output_path, int deb static int show_file_info(const char *path) { FILE *f = fopen(path, "rb"); if (!f) { - fprintf(stderr, "Error: Cannot open file '%s'\n", path); + fprintf(stderr, "%serror:%s Cannot open file '%s'\n", C_ERROR, C_RESET, path); return 1; } @@ -457,13 +458,13 @@ static int show_file_info(const char *path) { // Read header uint32_t magic; if (fread(&magic, 4, 1, f) != 1) { - fprintf(stderr, "Error: Cannot read file header\n"); + fprintf(stderr, "%serror:%s Cannot read file header\n", C_ERROR, C_RESET); fclose(f); return 1; } - printf("=== File Info: %s ===\n", path); - printf("Size: %ld bytes\n", file_size); + printf("%s%s=== File Info: %s ===%s\n", C_BOLD, C_CYAN, path, C_RESET); + printf("Size: %s%ld%s bytes\n", C_CODE, file_size, C_RESET); if (magic == 0x434C4D48) { // "HMLC" uint16_t version, flags; @@ -473,26 +474,26 @@ static int show_file_info(const char *path) { fread(&flags, 2, 1, f) != 1 || fread(&string_count, 4, 1, f) != 1 || fread(&stmt_count, 4, 1, f) != 1) { - fprintf(stderr, "Error: Cannot read HMLC header\n"); + fprintf(stderr, "%serror:%s Cannot read HMLC header\n", C_ERROR, C_RESET); fclose(f); return 1; } - printf("Format: HMLC (compiled AST)\n"); - printf("Version: %d\n", version); - printf("Flags: 0x%04x", flags); - if (flags & 0x0001) printf(" [DEBUG]"); - if (flags & 0x0002) printf(" [COMPRESSED]"); + printf("Format: %sHMLC%s (compiled AST)\n", C_GREEN, C_RESET); + printf("Version: %s%d%s\n", C_CODE, version, C_RESET); + printf("Flags: %s0x%04x%s", C_CODE, flags, C_RESET); + if (flags & 0x0001) printf(" %s[DEBUG]%s", C_YELLOW, C_RESET); + if (flags & 0x0002) printf(" %s[COMPRESSED]%s", C_CYAN, C_RESET); printf("\n"); - printf("Strings: %u\n", string_count); - printf("Statements: %u\n", stmt_count); + printf("Strings: %s%u%s\n", C_CODE, string_count, C_RESET); + printf("Statements: %s%u%s\n", C_CODE, stmt_count, C_RESET); } else if (magic == 0x424C4D48) { // "HMLB" uint16_t version; uint32_t orig_size; if (fread(&version, 2, 1, f) != 1 || fread(&orig_size, 4, 1, f) != 1) { - fprintf(stderr, "Error: Cannot read HMLB header\n"); + fprintf(stderr, "%serror:%s Cannot read HMLB header\n", C_ERROR, C_RESET); fclose(f); return 1; } @@ -500,13 +501,13 @@ static int show_file_info(const char *path) { long compressed_size = file_size - 10; // Header is 10 bytes double ratio = (1.0 - (double)compressed_size / orig_size) * 100; - printf("Format: HMLB (compressed bundle)\n"); - printf("Version: %d\n", version); - printf("Uncompressed: %u bytes\n", orig_size); - printf("Compressed: %ld bytes\n", compressed_size); - printf("Ratio: %.1f%% reduction\n", ratio); + printf("Format: %sHMLB%s (compressed bundle)\n", C_GREEN, C_RESET); + printf("Version: %s%d%s\n", C_CODE, version, C_RESET); + printf("Uncompressed: %s%u%s bytes\n", C_CODE, orig_size, C_RESET); + printf("Compressed: %s%ld%s bytes\n", C_CODE, compressed_size, C_RESET); + printf("Ratio: %s%.1f%%%s reduction\n", C_SUCCESS, ratio, C_RESET); } else { - printf("Format: Unknown (magic: 0x%08x)\n", magic); + printf("Format: %sUnknown%s (magic: 0x%08x)\n", C_WARNING, C_RESET, magic); } fclose(f); @@ -857,11 +858,27 @@ static void run_repl(int stack_depth) { register_builtins(env, 0, NULL, ctx); - printf("Hemlock v%s REPL\n", HEMLOCK_VERSION); - printf("Type 'exit' to quit\n\n"); + // Print sexy REPL header + if (term_color_enabled()) { + printf("\n"); + printf("%s *%s\n", C_GREEN, C_RESET); + printf("%s /|\\%s\n", C_GREEN, C_RESET); + printf("%s /_|_\\%s\n", C_GREEN, C_RESET); + printf("%s /__|__\\%s\n", C_GREEN, C_RESET); + printf("%s /___|___\\%s\n", C_GREEN, C_RESET); + printf("%s |%s\n", C_YELLOW, C_RESET); + printf("\n"); + printf(" %s%sHemlock%s v%s%s%s\n", C_BOLD, C_GREEN, C_RESET, C_ACCENT, HEMLOCK_VERSION, C_RESET); + printf(" %sA small, unsafe language for writing unsafe things safely.%s\n", C_MUTED, C_RESET); + printf("\n"); + printf(" %sType %s'exit'%s%s to quit, or start typing code.%s\n\n", C_MUTED, C_CODE, C_RESET, C_MUTED, C_RESET); + } else { + printf("\nHemlock v%s REPL\n", HEMLOCK_VERSION); + printf("Type 'exit' to quit\n\n"); + } for (;;) { - printf(">>> "); + printf("%s>>>%s ", C_GREEN, C_RESET); if (!fgets(line, sizeof(line), stdin)) { printf("\n"); @@ -925,75 +942,84 @@ static void run_repl(int stack_depth) { } static void print_version(void) { - printf("Hemlock version %s (built %s %s)\n", HEMLOCK_VERSION, HEMLOCK_BUILD_DATE, HEMLOCK_BUILD_TIME); - printf("A small, unsafe language for writing unsafe things safely.\n"); + printf("%s%sHemlock%s version %s%s%s %s(built %s %s)%s\n", + C_BOLD, C_GREEN, C_RESET, + C_ACCENT, HEMLOCK_VERSION, C_RESET, + C_MUTED, HEMLOCK_BUILD_DATE, HEMLOCK_BUILD_TIME, C_RESET); + printf("%sA small, unsafe language for writing unsafe things safely.%s\n", C_MUTED, C_RESET); } static void print_help(const char *program) { - printf("Hemlock - A systems scripting language\n\n"); - printf("USAGE:\n"); - printf(" %s [OPTIONS] [FILE] [ARGS...]\n", program); - printf(" %s --compile FILE [-o OUTPUT] [--debug]\n", program); - printf(" %s --bundle FILE [-o OUTPUT] [--compress] [--tree-shake] [--verbose]\n", program); - printf(" %s --package FILE [-o OUTPUT] [--no-compress] [--tree-shake] [--verbose]\n", program); - printf(" %s format FILE [--check]\n", program); - printf(" %s lsp [--stdio | --tcp PORT]\n\n", program); - printf("ARGUMENTS:\n"); - printf(" Hemlock script file to execute (.hml or .hmlc)\n"); - printf(" ... Arguments passed to the script (available in 'args' array)\n\n"); - printf("SUBCOMMANDS:\n"); - printf(" format Format Hemlock source code\n"); - printf(" --check Check if file is formatted (exit 1 if not)\n"); - printf(" lsp Start Language Server Protocol server\n"); - printf(" --stdio Use stdio transport (default)\n"); - printf(" --tcp PORT Use TCP transport on specified port\n"); - printf(" profile Profile script execution (CPU time, memory, call counts)\n"); - printf(" --cpu CPU/time profiling (default)\n"); - printf(" --memory Memory allocation profiling\n"); - printf(" --json Output in JSON format\n"); - printf(" --flamegraph Output in flamegraph-compatible format\n"); - printf(" --top N Show top N entries (default: 20)\n\n"); - printf("OPTIONS:\n"); - printf(" -h, --help Display this help message\n"); - printf(" -v, --version Display version information\n"); - printf(" -i, --interactive Start REPL after executing file\n"); - printf(" -e, -c, --command \n"); + // Header + printf("%s%sHemlock%s %s- A systems scripting language%s\n\n", C_BOLD, C_GREEN, C_RESET, C_MUTED, C_RESET); + + // Usage + printf("%s%sUSAGE%s\n", C_BOLD, C_YELLOW, C_RESET); + printf(" %s%s%s [OPTIONS] [FILE] [ARGS...]\n", C_CODE, program, C_RESET); + printf(" %s%s%s --compile FILE [-o OUTPUT] [--debug]\n", C_CODE, program, C_RESET); + printf(" %s%s%s --bundle FILE [-o OUTPUT] [--compress] [--tree-shake] [--verbose]\n", C_CODE, program, C_RESET); + printf(" %s%s%s --package FILE [-o OUTPUT] [--no-compress] [--tree-shake] [--verbose]\n", C_CODE, program, C_RESET); + printf(" %s%s%s format FILE [--check]\n", C_CODE, program, C_RESET); + printf(" %s%s%s lsp [--stdio | --tcp PORT]\n\n", C_CODE, program, C_RESET); + + // Arguments + printf("%s%sARGUMENTS%s\n", C_BOLD, C_YELLOW, C_RESET); + printf(" %s%s Hemlock script file to execute (.hml or .hmlc)\n", C_CYAN, C_RESET); + printf(" %s...%s Arguments passed to the script (available in 'args' array)\n\n", C_CYAN, C_RESET); + + // Subcommands + printf("%s%sSUBCOMMANDS%s\n", C_BOLD, C_YELLOW, C_RESET); + printf(" %sformat%s Format Hemlock source code\n", C_GREEN, C_RESET); + printf(" %s--check%s Check if file is formatted (exit 1 if not)\n", C_MUTED, C_RESET); + printf(" %slsp%s Start Language Server Protocol server\n", C_GREEN, C_RESET); + printf(" %s--stdio%s Use stdio transport (default)\n", C_MUTED, C_RESET); + printf(" %s--tcp PORT%s Use TCP transport on specified port\n", C_MUTED, C_RESET); + printf(" %sprofile%s Profile script execution (CPU time, memory, call counts)\n", C_GREEN, C_RESET); + printf(" %s--cpu%s CPU/time profiling (default)\n", C_MUTED, C_RESET); + printf(" %s--memory%s Memory allocation profiling\n", C_MUTED, C_RESET); + printf(" %s--json%s Output in JSON format\n", C_MUTED, C_RESET); + printf(" %s--flamegraph%s Output in flamegraph-compatible format\n", C_MUTED, C_RESET); + printf(" %s--top N%s Show top N entries (default: 20)\n\n", C_MUTED, C_RESET); + + // Options + printf("%s%sOPTIONS%s\n", C_BOLD, C_YELLOW, C_RESET); + printf(" %s-h, --help%s Display this help message\n", C_CYAN, C_RESET); + printf(" %s-v, --version%s Display version information\n", C_CYAN, C_RESET); + printf(" %s-i, --interactive%s Start REPL after executing file\n", C_CYAN, C_RESET); + printf(" %s-e, -c, --command%s \n", C_CYAN, C_RESET); printf(" Execute code string directly\n"); - printf(" --compile Compile .hml to binary AST (.hmlc)\n"); - printf(" --bundle Bundle .hml with all imports into single file\n"); - printf(" --package Create self-contained executable (interpreter + bundle)\n"); - printf(" --compress Use zlib compression for bundle output (.hmlb)\n"); - printf(" --tree-shake Remove unused exports from bundle (dead code elimination)\n"); - printf(" --no-compress Skip compression (faster startup, larger binary)\n"); - printf(" --info Show info about a .hmlc/.hmlb file\n"); - printf(" -o, --output Output path for compiled/bundled/packaged file\n"); - printf(" --debug Include line numbers in compiled output\n"); - printf(" --verbose Print progress during bundling/packaging\n"); - printf(" --stack-depth Set maximum call stack depth (default: 10000)\n"); - printf(" --sandbox [DIR] Run in sandbox mode (restricts dangerous operations)\n"); - printf(" Disables: FFI, network, process spawning, file writes,\n"); - printf(" signals (signal, raise, kill, abort)\n"); - printf(" If DIR provided, restricts file reads to that directory\n\n"); - printf("EXAMPLES:\n"); - printf(" %s # Start interactive REPL\n", program); - printf(" %s script.hml # Run script.hml\n", program); - printf(" %s script.hmlc # Run compiled script\n", program); - printf(" %s script.hml arg1 arg2 # Run script with arguments\n", program); - printf(" %s -e 'print(\"Hello\");' # Execute code string (one-liner)\n", program); - printf(" %s -i script.hml # Run script then start REPL\n", program); - printf(" %s --compile script.hml # Compile to script.hmlc\n", program); - printf(" %s --compile src.hml -o out.hmlc --debug\n", program); - printf(" %s --bundle app.hml # Bundle app.hml + imports -> app.hmlc\n", program); - printf(" %s --bundle app.hml --compress -o app.hmlb\n", program); - printf(" %s --package app.hml # Create ./app executable\n", program); - printf(" %s --package app.hml --no-compress -o myapp\n", program); - printf(" %s --info app.hmlc # Show compiled file info\n", program); - printf(" %s --stack-depth 50000 script.hml # Run with larger stack\n", program); - printf(" %s lsp # Start LSP server (stdio)\n", program); - printf(" %s lsp --tcp 6969 # Start LSP server (TCP)\n", program); - printf(" %s --sandbox script.hml # Run in sandbox mode\n", program); - printf(" %s --sandbox /tmp script.hml # Sandbox with /tmp as allowed dir\n\n", program); - printf("For more information, visit: https://github.com/hemlang/hemlock\n"); + printf(" %s--compile%s Compile .hml to binary AST (.hmlc)\n", C_CYAN, C_RESET); + printf(" %s--bundle%s Bundle .hml with all imports into single file\n", C_CYAN, C_RESET); + printf(" %s--package%s Create self-contained executable (interpreter + bundle)\n", C_CYAN, C_RESET); + printf(" %s--compress%s Use zlib compression for bundle output (.hmlb)\n", C_CYAN, C_RESET); + printf(" %s--tree-shake%s Remove unused exports from bundle (dead code elimination)\n", C_CYAN, C_RESET); + printf(" %s--no-compress%s Skip compression (faster startup, larger binary)\n", C_CYAN, C_RESET); + printf(" %s--info%s Show info about a .hmlc/.hmlb file\n", C_CYAN, C_RESET); + printf(" %s-o, --output%s Output path for compiled/bundled/packaged file\n", C_CYAN, C_RESET); + printf(" %s--debug%s Include line numbers in compiled output\n", C_CYAN, C_RESET); + printf(" %s--verbose%s Print progress during bundling/packaging\n", C_CYAN, C_RESET); + printf(" %s--stack-depth%s Set maximum call stack depth (default: 10000)\n", C_CYAN, C_RESET); + printf(" %s--sandbox%s [DIR] Run in sandbox mode (restricts dangerous operations)\n", C_CYAN, C_RESET); + printf(" %sDisables: FFI, network, process spawning, file writes,%s\n", C_MUTED, C_RESET); + printf(" %ssignals (signal, raise, kill, abort)%s\n", C_MUTED, C_RESET); + printf(" %sIf DIR provided, restricts file reads to that directory%s\n\n", C_MUTED, C_RESET); + + // Examples + printf("%s%sEXAMPLES%s\n", C_BOLD, C_YELLOW, C_RESET); + printf(" %s%s%s %s# Start interactive REPL%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s script.hml%s %s# Run script.hml%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s script.hmlc%s %s# Run compiled script%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s script.hml arg1 arg2%s %s# Run script with arguments%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s -e 'print(\"Hello\");'%s %s# Execute code string%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s -i script.hml%s %s# Run script then start REPL%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s --compile script.hml%s %s# Compile to script.hmlc%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s --bundle app.hml%s %s# Bundle app.hml + imports%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s --package app.hml%s %s# Create ./app executable%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s lsp%s %s# Start LSP server%s\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + printf(" %s%s --sandbox script.hml%s %s# Run in sandbox mode%s\n\n", C_CODE, program, C_RESET, C_MUTED, C_RESET); + + // Footer + printf("%sFor more information, visit: %s%shttps://github.com/hemlang/hemlock%s\n", C_MUTED, C_RESET, C_UNDERLINE, C_RESET); } // Run profiler @@ -1052,7 +1078,7 @@ static int run_profile(int argc, char **argv) { printf(" hemlock profile --flamegraph script.hml | flamegraph.pl > out.svg\n"); return 0; } else if (argv[i][0] == '-') { - fprintf(stderr, "Error: Unknown option '%s'\n", argv[i]); + fprintf(stderr, "%serror:%s Unknown option '%s'\n", C_ERROR, C_RESET, argv[i]); fprintf(stderr, "Try 'hemlock profile --help' for more information.\n"); return 1; } else { @@ -1064,7 +1090,7 @@ static int run_profile(int argc, char **argv) { } if (!file_to_run) { - fprintf(stderr, "Error: No input file specified\n"); + fprintf(stderr, "%serror:%s No input file specified\n", C_ERROR, C_RESET); fprintf(stderr, "Usage: hemlock profile [OPTIONS] [ARGS...]\n"); return 1; } @@ -1079,7 +1105,7 @@ static int run_profile(int argc, char **argv) { char *source = NULL; FILE *f = fopen(file_to_run, "rb"); if (!f) { - fprintf(stderr, "Error: Could not open file '%s'\n", file_to_run); + fprintf(stderr, "%serror:%s Could not open file '%s'\n", C_ERROR, C_RESET, file_to_run); profiler_free(profiler); return 1; } @@ -1087,7 +1113,7 @@ static int run_profile(int argc, char **argv) { fseek(f, 0, SEEK_END); long size = ftell(f); if (fseek(f, 0, SEEK_SET) != 0) { - fprintf(stderr, "Error: Could not seek to beginning of file\n"); + fprintf(stderr, "%serror:%s Could not seek to beginning of file\n", C_ERROR, C_RESET); fclose(f); profiler_free(profiler); return 1; @@ -1095,7 +1121,7 @@ static int run_profile(int argc, char **argv) { source = malloc(size + 1); size_t bytes_read = fread(source, 1, size, f); if ((long)bytes_read != size) { - fprintf(stderr, "Error: Could not read complete file (read %zu of %ld bytes)\n", bytes_read, size); + fprintf(stderr, "%serror:%s Could not read complete file (read %zu of %ld bytes)\n", C_ERROR, C_RESET, bytes_read, size); free(source); fclose(f); profiler_free(profiler); @@ -1154,7 +1180,7 @@ static int run_profile(int argc, char **argv) { if (output_file) { output = fopen(output_file, "w"); if (!output) { - fprintf(stderr, "Error: Could not open output file '%s'\n", output_file); + fprintf(stderr, "%serror:%s Could not open output file '%s'\n", C_ERROR, C_RESET, output_file); output = stdout; } } @@ -1260,7 +1286,7 @@ static int run_format(int argc, char **argv) { printf(" - Single blank line maximum\n"); return 0; } else if (argv[i][0] == '-') { - fprintf(stderr, "Error: Unknown option '%s'\n", argv[i]); + fprintf(stderr, "%serror:%s Unknown option '%s'\n", C_ERROR, C_RESET, argv[i]); fprintf(stderr, "Try 'hemlock format --help' for more information.\n"); return 1; } else { @@ -1269,7 +1295,7 @@ static int run_format(int argc, char **argv) { } if (file_to_format == NULL) { - fprintf(stderr, "Error: No input file specified\n"); + fprintf(stderr, "%serror:%s No input file specified\n", C_ERROR, C_RESET); fprintf(stderr, "Try 'hemlock format --help' for more information.\n"); return 1; } @@ -1353,7 +1379,7 @@ int main(int argc, char **argv) { interactive_mode = 1; } else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--command") == 0) { if (i + 1 >= argc) { - fprintf(stderr, "Error: -e/-c/--command requires a code argument\n"); + fprintf(stderr, "%serror:%s -e/-c/--command requires a code argument\n", C_ERROR, C_RESET); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } @@ -1362,7 +1388,7 @@ int main(int argc, char **argv) { } else if (strcmp(argv[i], "--compile") == 0) { compile_mode = 1; if (i + 1 >= argc) { - fprintf(stderr, "Error: --compile requires a file argument\n"); + fprintf(stderr, "%serror:%s --compile requires a file argument\n", C_ERROR, C_RESET); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } @@ -1370,7 +1396,7 @@ int main(int argc, char **argv) { i++; // Skip the file argument } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) { if (i + 1 >= argc) { - fprintf(stderr, "Error: -o/--output requires a file argument\n"); + fprintf(stderr, "%serror:%s -o/--output requires a file argument\n", C_ERROR, C_RESET); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } @@ -1381,7 +1407,7 @@ int main(int argc, char **argv) { } else if (strcmp(argv[i], "--bundle") == 0) { bundle_mode = 1; if (i + 1 >= argc) { - fprintf(stderr, "Error: --bundle requires a file argument\n"); + fprintf(stderr, "%serror:%s --bundle requires a file argument\n", C_ERROR, C_RESET); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } @@ -1397,20 +1423,20 @@ int main(int argc, char **argv) { bundle_tree_shake = 1; } else if (strcmp(argv[i], "--stack-depth") == 0) { if (i + 1 >= argc) { - fprintf(stderr, "Error: --stack-depth requires a numeric argument\n"); + fprintf(stderr, "%serror:%s --stack-depth requires a numeric argument\n", C_ERROR, C_RESET); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } stack_depth = atoi(argv[i + 1]); if (stack_depth <= 0) { - fprintf(stderr, "Error: --stack-depth must be a positive integer\n"); + fprintf(stderr, "%serror:%s --stack-depth must be a positive integer\n", C_ERROR, C_RESET); return 1; } i++; // Skip the value argument } else if (strcmp(argv[i], "--info") == 0) { info_mode = 1; if (i + 1 >= argc) { - fprintf(stderr, "Error: --info requires a file argument\n"); + fprintf(stderr, "%serror:%s --info requires a file argument\n", C_ERROR, C_RESET); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } @@ -1419,7 +1445,7 @@ int main(int argc, char **argv) { } else if (strcmp(argv[i], "--package") == 0) { package_mode = 1; if (i + 1 >= argc) { - fprintf(stderr, "Error: --package requires a file argument\n"); + fprintf(stderr, "%serror:%s --package requires a file argument\n", C_ERROR, C_RESET); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } @@ -1447,7 +1473,7 @@ int main(int argc, char **argv) { } } else if (argv[i][0] == '-') { // Unknown flag - fprintf(stderr, "Error: Unknown option '%s'\n", argv[i]); + fprintf(stderr, "%serror:%s Unknown option '%s'\n", C_ERROR, C_RESET, argv[i]); fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return 1; } else { @@ -1463,7 +1489,7 @@ int main(int argc, char **argv) { // Handle compile mode if (compile_mode) { if (file_to_compile == NULL) { - fprintf(stderr, "Error: No input file specified for compilation\n"); + fprintf(stderr, "%serror:%s No input file specified for compilation\n", C_ERROR, C_RESET); return 1; } int result = compile_file(file_to_compile, output_path, compile_debug); @@ -1473,7 +1499,7 @@ int main(int argc, char **argv) { // Handle bundle mode if (bundle_mode) { if (file_to_bundle == NULL) { - fprintf(stderr, "Error: No input file specified for bundling\n"); + fprintf(stderr, "%serror:%s No input file specified for bundling\n", C_ERROR, C_RESET); return 1; } int result = bundle_file(file_to_bundle, output_path, bundle_verbose, bundle_compress, bundle_tree_shake); @@ -1483,7 +1509,7 @@ int main(int argc, char **argv) { // Handle info mode if (info_mode) { if (file_to_info == NULL) { - fprintf(stderr, "Error: No input file specified for info\n"); + fprintf(stderr, "%serror:%s No input file specified for info\n", C_ERROR, C_RESET); return 1; } return show_file_info(file_to_info); @@ -1492,7 +1518,7 @@ int main(int argc, char **argv) { // Handle package mode if (package_mode) { if (file_to_package == NULL) { - fprintf(stderr, "Error: No input file specified for packaging\n"); + fprintf(stderr, "%serror:%s No input file specified for packaging\n", C_ERROR, C_RESET); return 1; } // For --package, compression is ON by default (smaller binary)