Felix Fietkau 8835ecf29b ucode-mod-uline: add support for querying window size from terminal if ioctl fails
This is useful for running the cli on a serial console

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2025-02-28 17:36:01 +01:00

153 lines
3.3 KiB
C

// SPDX-License-Identifier: ISC
/*
* Copyright (C) 2025 Felix Fietkau <nbd@nbd.name>
*/
#ifndef __EDITLINE_H
#define __EDITLINE_H
#include <stdint.h>
#include <stdbool.h>
#include <termios.h>
#include <stdio.h>
#include <libubox/utils.h>
struct uline_state;
struct linebuf {
char *buf;
size_t len;
size_t bufsize;
char *prompt;
size_t pos;
size_t update_pos;
};
struct pos {
int16_t x;
int16_t y;
};
enum uline_event {
EDITLINE_EV_CURSOR_UP,
EDITLINE_EV_CURSOR_DOWN,
EDITLINE_EV_WINDOW_CHANGED,
EDITLINE_EV_LINE_INPUT,
EDITLINE_EV_INTERRUPT,
EDITLINE_EV_EOF,
};
struct uline_cb {
// called on every key input. return true if handled by callback
bool (*key_input)(struct uline_state *s, unsigned char c, unsigned int count);
void (*event)(struct uline_state *s, enum uline_event ev);
// line: called on newline, returns true to accept the line, false to keep
// editing a multi-line string
bool (*line)(struct uline_state *s, const char *str, size_t len);
// called on any changes to the buffer of the secondary line editor
void (*line2_update)(struct uline_state *s, const char *str, size_t len);
// called on cursor button press during line2 editing
// return true to handle in line2, false to handle in primary line
bool (*line2_cursor)(struct uline_state *s);
// called on newline on the secondary line editor
// return true to ignore, false to process as primary line newline event
bool (*line2_newline)(struct uline_state *s, const char *str, size_t len);
};
struct uline_state {
const struct uline_cb *cb;
int input;
FILE *output;
int sigwinch_count;
struct termios orig_termios;
bool has_termios;
struct linebuf line;
struct linebuf *line2;
unsigned int repeat_count;
char repeat_char;
unsigned int rows, cols;
struct pos cursor_pos;
struct pos end_pos;
bool ioctl_winsize;
bool full_update;
bool stop;
bool utf8;
char esc_seq[32];
int8_t esc_idx;
uint8_t utf8_cont;
};
void uline_init(struct uline_state *s, const struct uline_cb *cb,
int in_fd, FILE *out_stream, bool utf8);
void uline_poll(struct uline_state *s);
void uline_set_line(struct uline_state *s, const char *str, size_t len);
void uline_set_prompt(struct uline_state *s, const char *str);
static inline void
uline_set_cursor(struct uline_state *s, size_t pos)
{
s->line.pos = pos;
if (s->line.pos > s->line.len)
s->line.pos = s->line.len;
}
static inline void
uline_get_line(struct uline_state *s, const char **str, size_t *len)
{
if (s->line.buf) {
*str = s->line.buf;
*len = s->line.len;
} else{
*str = "";
*len = 0;
}
}
void uline_set_line2(struct uline_state *s, const char *str, size_t len);
void uline_set_line2_prompt(struct uline_state *s, const char *str);
static inline void
uline_set_line2_cursor(struct uline_state *s, size_t pos)
{
if (!s->line2)
return;
s->line2->pos = pos;
if (s->line2->pos > s->line2->len)
s->line2->pos = s->line2->len;
}
static inline void
uline_get_line2(struct uline_state *s, const char **str, size_t *len)
{
if (s->line2 && s->line2->buf) {
*str = s->line2->buf;
*len = s->line2->len;
} else{
*str = "";
*len = 0;
}
}
void uline_set_hint(struct uline_state *s, const char *str, size_t len);
void uline_hide_prompt(struct uline_state *s);
void uline_refresh_prompt(struct uline_state *s);
void uline_free(struct uline_state *s);
#endif