back to scratko.xyz
summaryrefslogtreecommitdiff
path: root/readline.c
blob: c36b19a55d92b5759ac78128a46ca510647cf30e (plain)
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "readline.h"
#include "shell.h"

#include <stdlib.h>
#include <string.h> /* memmove */
#include <stdio.h>

void readline_create_array(struct readline_type *readline)
{
    readline->arr = calloc(initial_size, 1);
    readline->cursor_pos = 0;
    readline->last_element_index = -1;
    readline->considered_index = 0;
    readline->allocation_size = initial_size;
}

static void readline_copy_array(struct readline_type *readline, char *new_arr)
{
    int i;
    for(i = 0; i <= readline->last_element_index; ++i)
        new_arr[i] = readline->arr[i];
}

static void readline_allocate_memory(struct readline_type *readline)
{
    char *new_arr = calloc(readline->allocation_size * 2, 1);
    readline_copy_array(readline, new_arr);
    free(readline->arr);
    readline->arr = new_arr;
    readline->allocation_size *= 2;
}

static void readline_reprint_modified_part(struct readline_type *readline,
                                           int begin_idx)
{
    int i, counter;
    for(i = begin_idx, counter = 0; i <= readline->last_element_index;
                                                            ++i, ++counter)
        putchar(readline->arr[i]);

    /* return cursor to previous position */
    for( ; counter != 0; --counter)
        putchar('\b');
    fflush(stdout);
}

void readline_add_char(struct readline_type *readline, int ch)
{
    char *begin_arr;
    int size;

    if(readline->last_element_index+1 == readline->allocation_size)
        readline_allocate_memory(readline);
    /* insert in middle position */
    if(readline->cursor_pos - 1 != readline->last_element_index) {
        begin_arr = readline->arr + readline->cursor_pos;
        size = readline->last_element_index - readline->cursor_pos + 1;
        memmove(begin_arr+1, begin_arr, size);
        readline->arr[readline->cursor_pos] = ch;
        ++readline->last_element_index;
        readline_reprint_modified_part(readline, readline->cursor_pos + 1);
    } else {
        ++readline->last_element_index;
        readline->arr[readline->last_element_index] = ch;
    }
    ++readline->cursor_pos;
}

void readline_reset_array(struct readline_type *readline)
{
    readline->last_element_index = -1;
    readline->cursor_pos = 0;
}

void readline_clear(struct readline_type *readline)
{
    free(readline->arr);
    readline->arr = NULL;
}

void readline_print(struct readline_type *readline)
{
    int i;
    for(i = 0; i <= readline->last_element_index; ++i)
        putchar(readline->arr[i]);
    readline->cursor_pos = readline->last_element_index + 1;
    fflush(stdout);
}

enum keys readline_detect_arrow_keys(int ch)
{
    char next_ch;
    if(ch == esc) {
        next_ch = getchar();
        if(next_ch != '[')
            return unknown_key;
        next_ch = getchar();

        switch(next_ch) {
        case left_arrow:
            return left_arrow;
        case right_arrow:
            return right_arrow;
        case up_arrow:
            return up_arrow;
        case down_arrow:
            return down_arrow;
        default:
            return unknown_key;
        }
    }
    return none;
}

void readline_move_along(struct readline_type *readline, enum keys found_key)
{
    switch(found_key) {
    case left_arrow:
        if(readline->cursor_pos > 0) {
            putchar('\b');
            fflush(stdout);
            --readline->cursor_pos;
        }
        break;
    case right_arrow:
        if(readline->cursor_pos <= readline->last_element_index) {
            putchar(readline->arr[readline->cursor_pos]);
            fflush(stdout);
            ++readline->cursor_pos;
        }
        break;
    default:
        ;
    }
}

void readline_character_deletion(struct readline_type *readline)
{
    char *begin_arr;
    int size;

    if(readline->cursor_pos > 0) {
        putchar('\b');
        fflush(stdout);
        begin_arr = readline->arr + readline->cursor_pos;
        size = readline->last_element_index - readline->cursor_pos + 1;
        memmove(begin_arr-1, begin_arr, size);
        readline->arr[readline->last_element_index] = ' ';
        readline_reprint_modified_part(readline, readline->cursor_pos - 1);
        --readline->last_element_index;
        --readline->cursor_pos;
    }
}