| ... | ... |
@@ -93,7 +93,9 @@ static void draw(tty_interface_t *state) {
|
| 93 | 93 |
if (num_lines > 0) {
|
| 94 | 94 |
tty_moveup(tty, num_lines); |
| 95 | 95 |
} |
| 96 |
- tty_setcol(tty, strlen(options->prompt) + strlen(state->search)); |
|
| 96 |
+ |
|
| 97 |
+ int length = strlen(options->prompt) + strlen(state->search); |
|
| 98 |
+ tty_setcol(tty, length + state->offset); |
|
| 97 | 99 |
tty_flush(tty); |
| 98 | 100 |
} |
| 99 | 101 |
|
| ... | ... |
@@ -131,8 +133,15 @@ static void action_emit(tty_interface_t *state) {
|
| 131 | 133 |
} |
| 132 | 134 |
|
| 133 | 135 |
static void action_del_char(tty_interface_t *state) {
|
| 134 |
- if (*state->search) |
|
| 135 |
- state->search[strlen(state->search) - 1] = '\0'; |
|
| 136 |
+ if (*state->search) {
|
|
| 137 |
+ int length = strlen(state->search); |
|
| 138 |
+ int index = length + state->offset - 1; |
|
| 139 |
+ if (index < 0) {
|
|
| 140 |
+ return; |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ memmove(&state->search[index], &state->search[index + 1], length - index); |
|
| 144 |
+ } |
|
| 136 | 145 |
} |
| 137 | 146 |
|
| 138 | 147 |
static void action_del_word(tty_interface_t *state) {
|
| ... | ... |
@@ -161,6 +170,24 @@ static void action_next(tty_interface_t *state) {
|
| 161 | 170 |
choices_next(state->choices); |
| 162 | 171 |
} |
| 163 | 172 |
|
| 173 |
+static void action_left(tty_interface_t *state) {
|
|
| 174 |
+ if ((unsigned long)abs(state->offset) < strlen(state->search)) |
|
| 175 |
+ state->offset--; |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+static void action_right(tty_interface_t *state) {
|
|
| 179 |
+ if (state->offset < 0) |
|
| 180 |
+ state->offset++; |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+static void action_beginning(tty_interface_t *state) {
|
|
| 184 |
+ state->offset = -strlen(state->search); |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+static void action_end(tty_interface_t *state) {
|
|
| 188 |
+ state->offset = 0; |
|
| 189 |
+} |
|
| 190 |
+ |
|
| 164 | 191 |
static void action_pageup(tty_interface_t *state) {
|
| 165 | 192 |
update_state(state); |
| 166 | 193 |
for(size_t i = 0; i < state->options->num_lines && state->choices->selection > 0; i++) |
| ... | ... |
@@ -192,8 +219,14 @@ static void append_search(tty_interface_t *state, char ch) {
|
| 192 | 219 |
char *search = state->search; |
| 193 | 220 |
size_t search_size = strlen(search); |
| 194 | 221 |
if (search_size < SEARCH_SIZE_MAX) {
|
| 195 |
- search[search_size++] = ch; |
|
| 196 |
- search[search_size] = '\0'; |
|
| 222 |
+ int location = state->offset + search_size; |
|
| 223 |
+ for (int i = search_size; i >= 0; i--) {
|
|
| 224 |
+ if (i >= location) {
|
|
| 225 |
+ search[i + 1] = search[i]; |
|
| 226 |
+ } |
|
| 227 |
+ } |
|
| 228 |
+ |
|
| 229 |
+ search[location] = ch; |
|
| 197 | 230 |
} |
| 198 | 231 |
} |
| 199 | 232 |
|
| ... | ... |
@@ -201,6 +234,7 @@ void tty_interface_init(tty_interface_t *state, tty_t *tty, choices_t *choices, |
| 201 | 234 |
state->tty = tty; |
| 202 | 235 |
state->choices = choices; |
| 203 | 236 |
state->options = options; |
| 237 |
+ state->offset = 0; |
|
| 204 | 238 |
|
| 205 | 239 |
strcpy(state->input, ""); |
| 206 | 240 |
strcpy(state->search, ""); |
| ... | ... |
@@ -233,7 +267,13 @@ static const keybinding_t keybindings[] = {{"\x7f", action_del_char}, /* DEL */
|
| 233 | 267 |
{KEY_CTRL('N'), action_next}, /* C-N */
|
| 234 | 268 |
{KEY_CTRL('K'), action_prev}, /* C-J */
|
| 235 | 269 |
{KEY_CTRL('J'), action_next}, /* C-K */
|
| 270 |
+ {KEY_CTRL('A'), action_beginning}, /* C-A */
|
|
| 271 |
+ {KEY_CTRL('E'), action_end}, /* C-E */
|
|
| 236 | 272 |
|
| 273 |
+ {"\x1bOD", action_left}, /* LEFT */
|
|
| 274 |
+ {"\x1b[D", action_left}, /* LEFT */
|
|
| 275 |
+ {"\x1bOC", action_right}, /* RIGHT */
|
|
| 276 |
+ {"\x1b[C", action_right}, /* RIGHT */
|
|
| 237 | 277 |
{"\x1b[A", action_prev}, /* UP */
|
| 238 | 278 |
{"\x1bOA", action_prev}, /* UP */
|
| 239 | 279 |
{"\x1b[B", action_next}, /* DOWN */
|