1
1
/*
2
2
* (Originally code for the Valery project)
3
- * Copyright (C) 2022-2023 Nicolai Brand (https://lytix.dev)
3
+ * Copyright (C) 2022-2024 Nicolai Brand (https://lytix.dev)
4
4
*
5
5
* This program is free software: you can redistribute it and/or modify
6
6
* it under the terms of the GNU General Public License as published by
26
26
#include "interactive/prompt.h"
27
27
28
28
29
- #define cursor_right (n ) printf("\033[%zuC", (size_t)(n))
30
- #define cursor_left (n ) printf("\033[%zuD", (size_t)(n))
31
- #define cursor_goto (x ) printf("\033[%zu", (size_t)(x))
32
- #define flush_line () printf("\33[2K\r")
29
+ #define CURSOR_LEFT (n ) printf("\033[%zuD", (size_t)(n))
30
+ #define FLUSH_LINE () printf("\33[2K\r")
31
+ #define PROMPT_ABS_POS (prompt ) (prompt)->cursor_pos_in_line + (prompt)->prev_line_end
33
32
34
33
35
34
typedef enum {
@@ -41,7 +40,8 @@ typedef enum {
41
40
KEY_ARROW_RIGHT = 67 ,
42
41
KEY_ARROW_LEFT = 68 ,
43
42
44
- KEY_BACKSPACE = 127
43
+ KEY_BACKSPACE = 127 ,
44
+ KEY_TAB = '\t' ,
45
45
} PromptKey ;
46
46
47
47
@@ -65,11 +65,13 @@ static void termconf_end(Prompt *prompt)
65
65
66
66
static void prompt_show (Prompt * prompt )
67
67
{
68
- flush_line ();
69
- printf ("%s%s" , prompt -> ps1 , prompt -> buf );
68
+ FLUSH_LINE ();
69
+ printf ("%s%s" , prompt -> ps1 , prompt -> buf + prompt -> prev_line_end );
70
70
/* move the cursor to its corresponding position */
71
- if (prompt -> cursor_pos != prompt -> buf_len )
72
- cursor_left (prompt -> buf_len - prompt -> cursor_pos );
71
+ if (PROMPT_ABS_POS (prompt ) != prompt -> buf_len ) {
72
+ ssize_t left_shift = PROMPT_ABS_POS (prompt ) - prompt -> buf_len ;
73
+ CURSOR_LEFT (- left_shift );
74
+ }
73
75
}
74
76
75
77
/* returns the type of arrow consumed from the terminal input buffer */
@@ -89,7 +91,6 @@ static void prompt_buf_ensure_capacity(Prompt *prompt)
89
91
/* -1 because we always have to have space for the sentinel null byte */
90
92
if (prompt -> buf_len >= prompt -> buf_cap - 1 ) {
91
93
prompt -> buf_cap *= 2 ;
92
- printf ("\nREALLOC\n\n" );
93
94
prompt -> buf = realloc (prompt -> buf , prompt -> buf_cap );
94
95
}
95
96
}
@@ -99,14 +100,15 @@ static void prompt_buf_append(Prompt *prompt, char c)
99
100
prompt_buf_ensure_capacity (prompt );
100
101
prompt -> buf [prompt -> buf_len ++ ] = c ;
101
102
prompt -> buf [prompt -> buf_len ] = 0 ;
102
- prompt -> cursor_pos ++ ;
103
+ prompt -> cursor_pos_in_line ++ ;
103
104
}
104
105
105
106
static void prompt_buf_remove_at_cursor (Prompt * prompt )
106
107
{
107
108
char tmp [prompt -> buf_len ];
108
- strncpy (tmp , prompt -> buf , prompt -> cursor_pos - 1 );
109
- strcpy (tmp + prompt -> cursor_pos - 1 , prompt -> buf + prompt -> cursor_pos );
109
+ size_t current_pos = PROMPT_ABS_POS (prompt );
110
+ strncpy (tmp , prompt -> buf , current_pos - 1 );
111
+ strcpy (tmp + current_pos - 1 , prompt -> buf + current_pos );
110
112
strcpy (prompt -> buf , tmp );
111
113
}
112
114
@@ -115,13 +117,14 @@ static void prompt_buf_insert_at_cursor(Prompt *prompt, char c)
115
117
/* ensure enough capacity for 'c' */
116
118
prompt_buf_ensure_capacity (prompt );
117
119
120
+ size_t current_pos = PROMPT_ABS_POS (prompt );
118
121
char tmp [prompt -> buf_len ];
119
- strncpy (tmp , prompt -> buf , prompt -> cursor_pos );
120
- tmp [prompt -> cursor_pos ] = c ;
121
- strcpy (tmp + prompt -> cursor_pos + 1 , prompt -> buf + prompt -> cursor_pos );
122
+ strncpy (tmp , prompt -> buf , current_pos );
123
+ tmp [current_pos ] = c ;
124
+ strcpy (tmp + current_pos + 1 , prompt -> buf + current_pos );
122
125
strcpy (prompt -> buf , tmp );
123
126
124
- prompt -> cursor_pos ++ ;
127
+ prompt -> cursor_pos_in_line ++ ;
125
128
prompt -> buf_len ++ ;
126
129
prompt_buf_ensure_capacity (prompt );
127
130
prompt -> buf [prompt -> buf_len ] = 0 ;
@@ -130,31 +133,37 @@ static void prompt_buf_insert_at_cursor(Prompt *prompt, char c)
130
133
static void handle_backspace (Prompt * prompt )
131
134
{
132
135
/* ignore backspace leftmost position */
133
- if (prompt -> cursor_pos == 0 )
136
+ if (prompt -> cursor_pos_in_line == 0 )
134
137
return ;
135
138
136
139
prompt_buf_remove_at_cursor (prompt );
137
- prompt -> cursor_pos -- ;
140
+ prompt -> cursor_pos_in_line -- ;
138
141
prompt -> buf_len -- ;
139
142
prompt -> buf [prompt -> buf_len ] = 0 ;
140
143
}
141
144
142
145
static void handle_arrow (Prompt * prompt )
143
146
{
144
147
PromptKey arrow = get_arrow_type ();
145
- if (arrow == KEY_ARROW_LEFT && prompt -> cursor_pos != 0 ) {
146
- cursor_left (1 );
147
- prompt -> cursor_pos -- ;
148
- } else if (arrow == KEY_ARROW_RIGHT && prompt -> cursor_pos != prompt -> buf_len ) {
149
- cursor_right (1 );
150
- prompt -> cursor_pos ++ ;
151
- }
148
+ if (arrow == KEY_ARROW_LEFT && prompt -> cursor_pos_in_line != 0 )
149
+ prompt -> cursor_pos_in_line -- ;
150
+ else if (arrow == KEY_ARROW_RIGHT && PROMPT_ABS_POS (prompt ) != prompt -> buf_len )
151
+ prompt -> cursor_pos_in_line ++ ;
152
152
}
153
153
154
+ static void prompt_reset (Prompt * prompt , bool continuation )
155
+ {
156
+ prompt -> cursor_pos_in_line = 0 ;
157
+ if (!continuation ) {
158
+ prompt -> prev_line_end = 0 ;
159
+ prompt -> buf_len = 0 ;
160
+ prompt -> buf [0 ] = 0 ;
161
+ }
162
+ }
154
163
155
- bool prompt_run (Prompt * prompt )
164
+ void prompt_run (Prompt * prompt , bool continuation )
156
165
{
157
- prompt_reset (prompt );
166
+ prompt_reset (prompt , continuation );
158
167
prompt_show (prompt );
159
168
char ch ;
160
169
while (EOF != (ch = getchar ()) && ch != '\n' ) {
@@ -167,8 +176,13 @@ bool prompt_run(Prompt *prompt)
167
176
handle_arrow (prompt );
168
177
break ;
169
178
179
+ case KEY_TAB :
180
+ for (size_t i = 0 ; i < 4 ; i ++ )
181
+ prompt_buf_insert_at_cursor (prompt , ' ' );
182
+ break ;
183
+
170
184
default :
171
- if (prompt -> cursor_pos == prompt -> buf_len )
185
+ if (PROMPT_ABS_POS ( prompt ) == prompt -> buf_len )
172
186
prompt_buf_append (prompt , ch );
173
187
else
174
188
prompt_buf_insert_at_cursor (prompt , ch );
@@ -177,43 +191,36 @@ bool prompt_run(Prompt *prompt)
177
191
prompt_show (prompt );
178
192
}
179
193
180
- // TODO: exit builtin means this branch is never taken
181
- if (strcmp (prompt -> buf , "exit" ) == 0 )
182
- return false;
183
-
184
- putchar ('\n' );
185
194
prompt_buf_append (prompt , '\n' );
186
195
prompt_buf_append (prompt , EOF );
187
- return true;
188
- }
196
+ prompt -> prev_line_end = prompt -> buf_len - 1 ; /* -1 because prev line ends before EOF */
189
197
190
- void prompt_reset (Prompt * prompt )
191
- {
192
- prompt -> cursor_pos = 0 ;
193
- prompt -> buf_len = 0 ;
194
- prompt -> buf [0 ] = 0 ;
198
+ putchar ('\n' );
195
199
}
196
200
197
-
198
- void prompt_init (Prompt * prompt , char * ps1 )
201
+ void prompt_set_ps1 (Prompt * prompt , char * ps1 )
199
202
{
200
- prompt -> cursor_pos = 0 ;
201
- /* init buffer */
202
- prompt -> buf_len = 0 ;
203
- prompt -> buf_cap = 1024 ;
204
- prompt -> buf = malloc (prompt -> buf_cap );
205
-
206
203
size_t ps1_len = 0 ;
207
204
if (ps1 != NULL )
208
205
ps1_len = strlen (ps1 );
209
206
if (ps1_len > 256 || ps1_len == 0 ) {
210
- strcpy (prompt -> ps1 , "->" );
207
+ strcpy (prompt -> ps1 , "-> " );
211
208
ps1_len = 2 ;
212
209
} else {
213
210
strncpy (prompt -> ps1 , ps1 , ps1_len );
214
211
}
215
212
prompt -> ps1 [ps1_len ] = 0 ;
213
+ }
216
214
215
+ void prompt_init (Prompt * prompt , char * ps1 )
216
+ {
217
+ prompt -> cursor_pos_in_line = 0 ;
218
+ prompt -> prev_line_end = 0 ;
219
+ /* init buffer */
220
+ prompt -> buf_len = 0 ;
221
+ prompt -> buf_cap = 1024 ;
222
+ prompt -> buf = malloc (prompt -> buf_cap );
223
+ prompt_set_ps1 (prompt , ps1 );
217
224
termconf_begin (prompt );
218
225
}
219
226
0 commit comments