VT100_CURSOR_WORD_LEFT,
VT100_CURSOR_RIGHT,
VT100_CURSOR_WORD_RIGHT,
+ VT100_CURSOR_POS,
VT100_HOME,
VT100_END,
VT100_INSERT,
};
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);
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
#ifdef TIOCGWINSZ
struct winsize ws = {};
- if (!ioctl(fileno(s->output), TIOCGWINSZ, &ws)) {
+ if (s->ioctl_winsize &&
+ !ioctl(fileno(s->output), TIOCGWINSZ, &ws)) {
if (ws.ws_col)
cols = ws.ws_col;
if (ws.ws_row)
rows = ws.ws_row;
- }
+ } else
#endif
+ {
+ s->ioctl_winsize = false;
+ }
s->sigwinch_count = sigwinch_count;
if (s->cols == cols && s->rows == rows)
}
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;
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;
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;
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) &&
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
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)
#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:
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;
}