Alien-libhisto

 view release on metacpan or  search on metacpan

bundled/tools/src/tui_term.c  view on Meta::CPAN

                    switch (seq[2]) {
                        case '1': ev.type = TUI_KEY_HOME; break;
                        case '3': ev.type = TUI_KEY_BACKSPACE; break;
                        case '4': ev.type = TUI_KEY_END; break;
                        case '5': ev.type = TUI_KEY_PAGE_UP; break;
                        case '6': ev.type = TUI_KEY_PAGE_DOWN; break;
                        case '7': ev.type = TUI_KEY_HOME; break;
                        case '8': ev.type = TUI_KEY_END; break;
                        default: break;
                    }
                }
            } else {
                switch (seq[2]) {
                    case 'A': ev.type = TUI_KEY_UP; break;
                    case 'B': ev.type = TUI_KEY_DOWN; break;
                    case 'C': ev.type = TUI_KEY_RIGHT; break;
                    case 'D': ev.type = TUI_KEY_LEFT; break;
                    case 'H': ev.type = TUI_KEY_HOME; break;
                    case 'F': ev.type = TUI_KEY_END; break;
                    default: break;
                }
            }
        } else if (seq[1] == 'O') {
            switch (seq[2]) {
                case 'H': ev.type = TUI_KEY_HOME; break;
                case 'F': ev.type = TUI_KEY_END; break;
                default: break;
            }
        }
        return ev;
    }

    if (c == 3) {
        ev.type = TUI_KEY_CTRL_C;
        ev.ch = 3;
        return ev;
    }
    if (c == 13 || c == 10) {
        ev.type = TUI_KEY_ENTER;
        ev.ch = '\n';
        return ev;
    }
    if (c == 9) {
        ev.type = TUI_KEY_TAB;
        ev.ch = '\t';
        return ev;
    }
    if (c == 127 || c == 8) {
        ev.type = TUI_KEY_BACKSPACE;
        ev.ch = '\b';
        return ev;
    }

    ev.type = TUI_KEY_CHAR;
    ev.ch = (unsigned char)c;
#endif
    return ev;
}

/* Frame buffer methods */
void tui_frame_init(tui_frame_t *f, size_t initial_cap) {
    if (!f) return;
    if (initial_cap < 4096) initial_cap = 65536;
    f->buf = (char *)malloc(initial_cap);
    f->len = 0;
    f->cap = initial_cap;
    if (f->buf) f->buf[0] = '\0';
}

void tui_frame_clear(tui_frame_t *f) {
    if (!f) return;
    f->len = 0;
    if (f->buf) f->buf[0] = '\0';
}

void tui_frame_append(tui_frame_t *f, const char *str, size_t len) {
    if (!f || !str || len == 0) return;
    if (f->len + len + 1 > f->cap) {
        size_t new_cap = (f->cap * 2 > f->len + len + 1) ? f->cap * 2 : f->len + len + 4096;
        char *new_buf = (char *)realloc(f->buf, new_cap);
        if (!new_buf) return;
        f->buf = new_buf;
        f->cap = new_cap;
    }
    memcpy(f->buf + f->len, str, len);
    f->len += len;
    f->buf[f->len] = '\0';
}

void tui_frame_puts(tui_frame_t *f, const char *str) {
    if (!f || !str) return;
    tui_frame_append(f, str, strlen(str));
}

void tui_frame_printf(tui_frame_t *f, const char *fmt, ...) {
    if (!f || !fmt) return;
    char stack_buf[1024];
    va_list args;
    va_start(args, fmt);
    int written = vsnprintf(stack_buf, sizeof(stack_buf), fmt, args);
    va_end(args);

    if (written < 0) return;
    if ((size_t)written < sizeof(stack_buf)) {
        tui_frame_append(f, stack_buf, (size_t)written);
    } else {
        char *heap_buf = (char *)malloc((size_t)written + 1);
        if (heap_buf) {
            va_start(args, fmt);
            vsnprintf(heap_buf, (size_t)written + 1, fmt, args);
            va_end(args);
            tui_frame_append(f, heap_buf, (size_t)written);
            free(heap_buf);
        }
    }
}

void tui_frame_flush(tui_frame_t *f, FILE *out_fp) {
    if (!f || !f->buf || f->len == 0) return;
    if (!out_fp) out_fp = stdout;
    fwrite(f->buf, 1, f->len, out_fp);
    fflush(out_fp);
    tui_frame_clear(f);
}

void tui_frame_free(tui_frame_t *f) {
    if (!f) return;
    if (f->buf) {
        free(f->buf);
        f->buf = NULL;
    }
    f->len = 0;
    f->cap = 0;
}

void tui_term_get_color(double fraction, bool monochrome, char *out_ansi, size_t max_len) {
    if (!out_ansi || max_len == 0) return;
    out_ansi[0] = '\0';
    if (monochrome) return;

    if (fraction < 0.0) fraction = 0.0;
    if (fraction > 1.0) fraction = 1.0;

    int r = 0, g = 0, b = 0;
    if (fraction < 0.25) {
        double t = fraction / 0.25;
        r = 0;
        g = (int)(t * 255.0);
        b = 255;
    } else if (fraction < 0.5) {
        double t = (fraction - 0.25) / 0.25;
        r = 0;
        g = 255;
        b = (int)((1.0 - t) * 255.0);
    } else if (fraction < 0.75) {
        double t = (fraction - 0.5) / 0.25;
        r = (int)(t * 255.0);
        g = 255;
        b = 0;
    } else {
        double t = (fraction - 0.75) / 0.25;
        r = 255;
        g = (int)((1.0 - t) * 255.0);
        b = 0;
    }
    snprintf(out_ansi, max_len, "\033[38;2;%d;%d;%dm", r, g, b);
}

int tui_visual_width(const char *str) {
    if (!str) return 0;
    int cols = 0;
    const unsigned char *p = (const unsigned char *)str;
    while (*p) {
        if (*p == '\033') {
            p++;
            if (*p == '[') {
                p++;
                while (*p && (*p < 0x40 || *p > 0x7E)) p++;
                if (*p) p++;
            }
        } else if (*p < 0x80) {
            if (*p >= 32 && *p <= 126) cols++;
            p++;
        } else if ((*p & 0xE0) == 0xC0) {
            cols++;
            p += (*(p + 1)) ? 2 : 1;
        } else if ((*p & 0xF0) == 0xE0) {
            cols++;
            p += (*(p + 1) && *(p + 2)) ? 3 : 1;
        } else if ((*p & 0xF8) == 0xF0) {
            cols += 2;
            p += (*(p + 1) && *(p + 2) && *(p + 3)) ? 4 : 1;
        } else {
            p++;
        }
    }
    return cols;
}

void tui_render_row(tui_frame_t *f, const char *content, int width, bool newline) {
    if (!f) return;
    tui_frame_puts(f, "│ ");
    int vis = tui_visual_width(content);
    int inner_width = width - 4;
    if (inner_width < 1) inner_width = 1;

    if (vis <= inner_width) {
        tui_frame_puts(f, content ? content : "");
        int pad = inner_width - vis;
        for (int i = 0; i < pad; ++i) tui_frame_puts(f, " ");
    } else {
        const unsigned char *p = (const unsigned char *)(content ? content : "");
        int cur_cols = 0;
        while (*p && cur_cols < inner_width) {
            if (*p == '\033') {
                const unsigned char *start = p++;
                if (*p == '[') {
                    p++;
                    while (*p && (*p < 0x40 || *p > 0x7E)) p++;
                    if (*p) p++;
                }
                tui_frame_append(f, (const char *)start, (size_t)(p - start));
            } else if (*p < 0x80) {
                if (*p >= 32 && *p <= 126) cur_cols++;
                tui_frame_append(f, (const char *)p, 1);
                p++;
            } else if ((*p & 0xE0) == 0xC0) {
                cur_cols++;
                size_t len = (*(p + 1)) ? 2 : 1;
                tui_frame_append(f, (const char *)p, len);
                p += len;
            } else if ((*p & 0xF0) == 0xE0) {
                cur_cols++;
                size_t len = (*(p + 1) && *(p + 2)) ? 3 : 1;
                tui_frame_append(f, (const char *)p, len);
                p += len;
            } else if ((*p & 0xF8) == 0xF0) {
                if (cur_cols + 2 <= inner_width) {
                    cur_cols += 2;
                    size_t len = (*(p + 1) && *(p + 2) && *(p + 3)) ? 4 : 1;
                    tui_frame_append(f, (const char *)p, len);
                    p += len;
                } else break;
            } else {
                p++;
            }
        }
        int pad = inner_width - cur_cols;
        for (int i = 0; i < pad; ++i) tui_frame_puts(f, " ");
    }

    tui_frame_puts(f, "\033[0m │");
    if (newline) tui_frame_puts(f, "\r\n");
}



( run in 0.451 second using v1.01-cache-2.11-cpan-2e0ccfb7a10 )