mirror of
git://git.openwrt.org/openwrt/openwrt.git
synced 2025-03-01 03:03:16 +00:00
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>
This commit is contained in:
parent
7953376400
commit
8835ecf29b
@ -52,6 +52,7 @@ enum vt100_escape {
|
||||
VT100_CURSOR_WORD_LEFT,
|
||||
VT100_CURSOR_RIGHT,
|
||||
VT100_CURSOR_WORD_RIGHT,
|
||||
VT100_CURSOR_POS,
|
||||
VT100_HOME,
|
||||
VT100_END,
|
||||
VT100_INSERT,
|
||||
@ -63,7 +64,7 @@ enum vt100_escape {
|
||||
};
|
||||
|
||||
ssize_t utf8_nsyms(const char *str, size_t len);
|
||||
enum vt100_escape vt100_esc_decode(const char *str);
|
||||
enum vt100_escape vt100_esc_decode(const char *str, uint32_t *data);
|
||||
|
||||
// helpers:
|
||||
void __vt100_csi_num(FILE *out, int num, char code);
|
||||
@ -191,4 +192,15 @@ static inline void vt100_ding(FILE *out)
|
||||
fflush(out);
|
||||
}
|
||||
|
||||
static inline void vt100_request_window_size(FILE *out)
|
||||
{
|
||||
fputs(
|
||||
"\e7" /* save cursor position */
|
||||
"\e[r" /* reset margins */
|
||||
"\e[999;999H" /* move cursor to bottom right */
|
||||
"\e[6n" /* report cursor position */
|
||||
"\e8", /* restore cursor position */
|
||||
out);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -101,13 +101,16 @@ update_window_size(struct uline_state *s, bool init)
|
||||
#ifdef TIOCGWINSZ
|
||||
struct winsize ws = {};
|
||||
|
||||
if (!ioctl(fileno(s->output), TIOCGWINSZ, &ws)) {
|
||||
if (ws.ws_col)
|
||||
cols = ws.ws_col;
|
||||
if (ws.ws_row)
|
||||
rows = ws.ws_row;
|
||||
}
|
||||
if (s->ioctl_winsize &&
|
||||
!ioctl(fileno(s->output), TIOCGWINSZ, &ws) &&
|
||||
ws.ws_col && ws.ws_row) {
|
||||
cols = ws.ws_col;
|
||||
rows = ws.ws_row;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
s->ioctl_winsize = false;
|
||||
}
|
||||
|
||||
s->sigwinch_count = sigwinch_count;
|
||||
if (s->cols == cols && s->rows == rows)
|
||||
@ -534,7 +537,7 @@ move_word_right(struct uline_state *s, struct linebuf *line)
|
||||
}
|
||||
|
||||
static bool
|
||||
process_esc(struct uline_state *s, enum vt100_escape esc)
|
||||
process_esc(struct uline_state *s, enum vt100_escape esc, uint32_t data)
|
||||
{
|
||||
struct linebuf *line = &s->line;
|
||||
|
||||
@ -552,6 +555,15 @@ process_esc(struct uline_state *s, enum vt100_escape esc)
|
||||
return move_right(s, line);
|
||||
case VT100_CURSOR_WORD_RIGHT:
|
||||
return move_word_right(s, line);
|
||||
case VT100_CURSOR_POS:
|
||||
if (s->rows == (data & 0xffff) &&
|
||||
s->cols == data >> 16)
|
||||
return false;
|
||||
s->rows = data & 0xffff;
|
||||
s->cols = data >> 16;
|
||||
s->full_update = true;
|
||||
s->cb->event(s, EDITLINE_EV_WINDOW_CHANGED);
|
||||
return true;
|
||||
case VT100_HOME:
|
||||
line->pos = 0;
|
||||
return true;
|
||||
@ -682,9 +694,9 @@ process_ctrl(struct uline_state *s, char c)
|
||||
linebuf_reset(line);
|
||||
return true;
|
||||
case KEY_SOH:
|
||||
return process_esc(s, VT100_HOME);
|
||||
return process_esc(s, VT100_HOME, 0);
|
||||
case KEY_ENQ:
|
||||
return process_esc(s, VT100_END);
|
||||
return process_esc(s, VT100_END, 0);
|
||||
case KEY_VT:
|
||||
// TODO: kill
|
||||
return false;
|
||||
@ -718,18 +730,19 @@ static void
|
||||
process_char(struct uline_state *s, char c)
|
||||
{
|
||||
enum vt100_escape esc;
|
||||
uint32_t data = 0;
|
||||
|
||||
check_key_repeat(s, c);
|
||||
if (s->esc_idx >= 0) {
|
||||
s->esc_seq[s->esc_idx++] = c;
|
||||
s->esc_seq[s->esc_idx] = 0;
|
||||
esc = vt100_esc_decode(s->esc_seq);
|
||||
esc = vt100_esc_decode(s->esc_seq, &data);
|
||||
if (esc == VT100_INCOMPLETE &&
|
||||
s->esc_idx < (int)sizeof(s->esc_seq) - 1)
|
||||
return;
|
||||
|
||||
s->esc_idx = -1;
|
||||
if (!process_esc(s, esc))
|
||||
if (!process_esc(s, esc, data))
|
||||
return;
|
||||
} else if (s->cb->key_input &&
|
||||
!check_utf8(s, (unsigned char )c) &&
|
||||
@ -901,7 +914,7 @@ void uline_init(struct uline_state *s, const struct uline_cb *cb,
|
||||
s->utf8 = utf8;
|
||||
s->input = in_fd;
|
||||
s->output = out_stream;
|
||||
update_window_size(s, true);
|
||||
s->ioctl_winsize = true;
|
||||
reset_input_state(s);
|
||||
|
||||
#ifdef USE_SYSTEM_WCHAR
|
||||
@ -916,6 +929,12 @@ void uline_init(struct uline_state *s, const struct uline_cb *cb,
|
||||
s->has_termios = true;
|
||||
termios_set_native_mode(s);
|
||||
}
|
||||
|
||||
update_window_size(s, true);
|
||||
if (!s->ioctl_winsize) {
|
||||
vt100_request_window_size(s->output);
|
||||
fflush(s->output);
|
||||
}
|
||||
}
|
||||
|
||||
void uline_free(struct uline_state *s)
|
||||
|
@ -82,12 +82,13 @@ struct uline_state {
|
||||
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[8];
|
||||
char esc_seq[32];
|
||||
int8_t esc_idx;
|
||||
uint8_t utf8_cont;
|
||||
};
|
||||
|
@ -7,10 +7,10 @@
|
||||
#include "uline.h"
|
||||
#include "private.h"
|
||||
|
||||
enum vt100_escape vt100_esc_decode(const char *str)
|
||||
enum vt100_escape vt100_esc_decode(const char *str, uint32_t *data)
|
||||
{
|
||||
unsigned long code;
|
||||
size_t idx;
|
||||
unsigned long code, code2;
|
||||
char *err;
|
||||
|
||||
switch (*(str++)) {
|
||||
case 0:
|
||||
@ -45,23 +45,36 @@ enum vt100_escape vt100_esc_decode(const char *str)
|
||||
case '0' ... '4':
|
||||
case '6' ... '9':
|
||||
str--;
|
||||
idx = strspn(str, "0123456789");
|
||||
if (!str[idx])
|
||||
code = strtoul(str, &err, 10);
|
||||
switch (*err) {
|
||||
case 0:
|
||||
return VT100_INCOMPLETE;
|
||||
if (str[idx] != '~')
|
||||
return VT100_UNKNOWN;
|
||||
code = strtoul(str, NULL, 10);
|
||||
switch (code) {
|
||||
case 1:
|
||||
return VT100_HOME;
|
||||
case 3:
|
||||
return VT100_DELETE;
|
||||
case 4:
|
||||
return VT100_END;
|
||||
case 200:
|
||||
case 201:
|
||||
// paste start/end
|
||||
return VT100_IGNORE;
|
||||
case '~':
|
||||
switch (code) {
|
||||
case 1:
|
||||
return VT100_HOME;
|
||||
case 3:
|
||||
return VT100_DELETE;
|
||||
case 4:
|
||||
return VT100_END;
|
||||
case 200:
|
||||
case 201:
|
||||
// paste start/end
|
||||
return VT100_IGNORE;
|
||||
default:
|
||||
return VT100_UNKNOWN;
|
||||
}
|
||||
case ';':
|
||||
code2 = strtoul(err + 1, &err, 10);
|
||||
switch (*err) {
|
||||
case 0:
|
||||
return VT100_INCOMPLETE;
|
||||
case 'R':
|
||||
*data = (code2 << 16) | (code & 0xffff);
|
||||
return VT100_CURSOR_POS;
|
||||
default:
|
||||
return VT100_UNKNOWN;
|
||||
}
|
||||
default:
|
||||
return VT100_UNKNOWN;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user