rewrite antirez's kilo in zig
const std = @import("std");
const os = std.os;

var origTermios: std.posix.termios = undefined;

var origTermios: os.termios = undefined;

pub fn main() anyerror!void {
    const stdin = std.io.getStdIn();
    defer disableRawMode(stdin);
    errdefer disableRawMode(stdin);
    enableRawMode(stdin) catch |err| {
        disableRawMode(stdin);
        std.log.err("unable to set termios state: {}", .{err});
        std.posix.exit(1);
    };
    defer disableRawMode(stdin);

    var ch: [1]u8 = undefined;
    while (!std.mem.eql(u8, &ch, &.{'q'})) : (_ = try stdin.read(&ch)) {
        if (std.ascii.isControl(ch[0])) {
            std.log.debug("{d}\r", .{ch});
        } else {
            std.log.debug("{d} {c}\r", .{ ch, ch });
        }
    }
}

fn enableRawMode(stdin: std.fs.File) anyerror!void {
    origTermios = try os.tcgetattr(stdin.handle);
    origTermios = try std.posix.tcgetattr(stdin.handle);

    var termState = origTermios;
    var termState = origTermios;
    try os.tcsetattr(stdin.handle, linux.TCSA.FLUSH, termState);
    // These are the flags for setting up raw mode (see man 3 termios)
    // The explanation is for the switched off state.
    // ~ECHO: not-repeating every input back to output
    // ~ECHONL:
    // ~ICANON: read input by bytes, no need to press <Enter> after every line
    // ~ISIG: send raw bytes instead of signals for the program (C-c, C-z etc.)
    // ~IEXTEN: disable (C-v) literal signal sending

    // ~IXON: disable flow control: suspend (C-s), resume (C-q)
    // ~ICRNL: disable C-m rewrite from \r to \n (from 13 to 10)
    // ~INLCR:
    // ~BRKINT, ~IGNBRK, ~PARMRK: BREAK reads as null byte ('\0')
    // ~ISTRIP: do not strip off 8th bit
    // ~IGNCR: do not ignore carrige return

    // ~OPOST: output post-processing: \n -> \r\n

    // ~CSIZE:
    // ~PARENB:

    // only in snapdragon's kilo:
    // ~INPCK: disable input parity check
    // termState.lflag &= ~@as(linux.tcflag_t, linux.ECHO | linux.ECHONL | linux.ICANON |
    //     linux.ISIG | linux.IEXTEN);
    // termState.iflag &= ~@as(linux.tcflag_t, linux.IXON | linux.ICRNL | linux.INLCR |
    //     linux.BRKINT | linux.IGNBRK | linux.PARMRK | linux.ISTRIP | linux.IGNCR);
    // termState.oflag &= ~@as(linux.tcflag_t, linux.OPOST);
    // termState.cflag &= ~@as(linux.tcflag_t, linux.CSIZE | linux.PARENB);
    termState.lflag = std.posix.tc_lflag_t{
        .ECHO = false,
        .ECHONL = false,
        .ICANON = false,
        .ISIG = false,
        .IEXTEN = false,
    };
    termState.iflag = std.posix.tc_iflag_t{
        .IXON = false,
        .ICRNL = false,
        .INLCR = false,
        .BRKINT = false,
        .IGNBRK = false,
        .PARMRK = false,
        .ISTRIP = false,
        .IGNCR = false,
    };
    termState.oflag = std.posix.tc_oflag_t{
        .OPOST = false,
    };
    termState.cflag = std.posix.tc_cflag_t{
        .CSIZE = .CS8,
        .PARENB = false,
    };

    // CS8 bit mask sets up character size to 8 bit/byte
    // termState.cflag |= linux.CS8;

    try std.posix.tcsetattr(stdin.handle, std.posix.TCSA.FLUSH, termState);
}

fn disableRawMode(stdin: std.fs.File) void {
    std.posix.tcsetattr(stdin.handle, std.posix.TCSA.FLUSH, origTermios) catch {};
}

fn disableRawMode(stdin: std.fs.File) void {
    os.tcsetattr(stdin.handle, linux.TCSA.FLUSH, origTermios) catch |err| {
        std.debug.print("{s}", .{err});
        return;
    };
}