summaryrefslogtreecommitdiff
path: root/src/user/libterm/readline.c
blob: b37801d800bc9bf93ea4a9402072bbdc8b93c3de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <libterm/terminal.h>

#include <knob/block.h>
#include <knob/key.h>

#include <stdint.h>

//returns length of string without null terminator
//max_length doesn't include null terminator
uint32_t read_line(char *sz, uint32_t max_length, const char *prompt) {
  term_add_sz(prompt);
  term_add_char(' ');
  term_paint();

  uint32_t l = 0;
  uint32_t c = 0;

  while (1) {
    struct key_packet kp = term_get_key_blocking();
    switch (kp.key_id) {
    case KEY_LEFT_ARROW:
      if (c) {
        --c;
        term_cursor_left();
        term_paint();
      }
      continue;
    case KEY_RIGHT_ARROW:
      if (c != l) {
        ++c;
        term_cursor_right();
        term_paint();
      }
      continue;
    case KEY_HOME:
      while (c) {
        --c;
        term_cursor_left();
      }
      term_paint();
      continue;
    case KEY_END:
      while (c != l) {
        ++c;
        term_cursor_right();
      }
      term_paint();
      continue;
    case KEY_DELETE:
      if (c != l) {
        ++c;
        term_cursor_right();
      }
    case KEY_BSPACE:
      if (!c)
        continue;
      --c;
      --l;
      for (uint32_t i = c; i < l; ++i)
        sz[i] = sz[i + 1];
      term_cursor_left();
      term_add_sn_no_ww(sz + c, l - c);
      term_add_char(' ');
      for (uint32_t i = l + 1; i > c; --i)
        term_cursor_left();
      term_paint();
      continue;
    case KEY_ENTER:
      while (c != l) {
        ++c;
        term_cursor_right();
      }
      sz[l] = '\0';
      term_add_char('\n');
      term_paint();
      return l;
    default:
      if (l == max_length)
        continue;
      char ch = key_to_char(kp);
      if (!ch)
        continue;
      if (c == l) {
        ++l;
        term_add_char(sz[c++] = ch);
        term_paint();
        continue;
      }
      if (!(kp.modifiers & INSERT)) {
        term_add_char(sz[c++] = ch);
        term_paint();
        continue;
      }
      for (uint32_t i = l; i > c; --i)
        sz[i] = sz[i - 1];
      sz[c] = ch;
      ++l;
      term_add_sn_no_ww(sz + c, l - c);
      ++c;
      for (uint32_t i = l; i > c; --i)
        term_cursor_left();
      term_paint();
      continue;
    }
  }
}