Skip to content

Commit 006f437

Browse files
tyomitchdpgeorge
authored andcommitted
py/repl: Refactor autocomplete to reduce nesting.
Originally at adafruit#4548 Signed-off-by: Artyom Skrobov <[email protected]>
1 parent 050bdd6 commit 006f437

File tree

1 file changed

+103
-100
lines changed

1 file changed

+103
-100
lines changed

py/repl.c

Lines changed: 103 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -161,131 +161,134 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
161161
mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__);
162162
mp_obj_t dest[2];
163163

164+
const char *s_start;
165+
size_t s_len;
166+
164167
for (;;) {
165168
// get next word in string to complete
166-
const char *s_start = str;
169+
s_start = str;
167170
while (str < top && *str != '.') {
168171
++str;
169172
}
170-
size_t s_len = str - s_start;
173+
s_len = str - s_start;
171174

172-
if (str < top) {
173-
// a complete word, lookup in current object
174-
qstr q = qstr_find_strn(s_start, s_len);
175-
if (q == MP_QSTRnull) {
176-
// lookup will fail
177-
return 0;
178-
}
179-
mp_load_method_protected(obj, q, dest, true);
180-
obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found
175+
if (str == top) {
176+
// end of string, do completion on this partial name
177+
break;
178+
}
181179

182-
if (obj == MP_OBJ_NULL) {
183-
// lookup failed
184-
return 0;
185-
}
180+
// a complete word, lookup in current object
181+
qstr q = qstr_find_strn(s_start, s_len);
182+
if (q == MP_QSTRnull) {
183+
// lookup will fail
184+
return 0;
185+
}
186+
mp_load_method_protected(obj, q, dest, true);
187+
obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found
186188

187-
// skip '.' to move to next word
188-
++str;
189+
if (obj == MP_OBJ_NULL) {
190+
// lookup failed
191+
return 0;
192+
}
189193

190-
} else {
191-
// end of string, do completion on this partial name
194+
// skip '.' to move to next word
195+
++str;
196+
}
192197

193-
// look for matches
194-
const char *match_str = NULL;
195-
size_t match_len = 0;
196-
qstr q_first = 0, q_last = 0;
197-
for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) {
198-
size_t d_len;
199-
const char *d_str = (const char *)qstr_data(q, &d_len);
200-
// special case; filter out words that begin with underscore
201-
// unless there's already a partial match
202-
if (s_len == 0 && d_str[0] == '_') {
203-
continue;
204-
}
205-
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
206-
mp_load_method_protected(obj, q, dest, true);
207-
if (dest[0] != MP_OBJ_NULL) {
208-
if (match_str == NULL) {
209-
match_str = d_str;
210-
match_len = d_len;
211-
} else {
212-
// search for longest common prefix of match_str and d_str
213-
// (assumes these strings are null-terminated)
214-
for (size_t j = s_len; j <= match_len && j <= d_len; ++j) {
215-
if (match_str[j] != d_str[j]) {
216-
match_len = j;
217-
break;
218-
}
219-
}
220-
}
221-
if (q_first == 0) {
222-
q_first = q;
198+
// look for matches
199+
const char *match_str = NULL;
200+
size_t match_len = 0;
201+
qstr q_first = 0, q_last = 0;
202+
for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) {
203+
size_t d_len;
204+
const char *d_str = (const char *)qstr_data(q, &d_len);
205+
// special case; filter out words that begin with underscore
206+
// unless there's already a partial match
207+
if (s_len == 0 && d_str[0] == '_') {
208+
continue;
209+
}
210+
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
211+
mp_load_method_protected(obj, q, dest, true);
212+
if (dest[0] != MP_OBJ_NULL) {
213+
if (match_str == NULL) {
214+
match_str = d_str;
215+
match_len = d_len;
216+
} else {
217+
// search for longest common prefix of match_str and d_str
218+
// (assumes these strings are null-terminated)
219+
for (size_t j = s_len; j <= match_len && j <= d_len; ++j) {
220+
if (match_str[j] != d_str[j]) {
221+
match_len = j;
222+
break;
223223
}
224-
q_last = q;
225224
}
226225
}
227-
}
228-
229-
// nothing found
230-
if (q_first == 0) {
231-
if (s_len == 0) {
232-
*compl_str = " ";
233-
return 4;
226+
if (q_first == 0) {
227+
q_first = q;
234228
}
235-
// If there're no better alternatives, and if it's first word
236-
// in the line, try to complete "import".
237-
if (s_start == org_str) {
238-
static const char import_str[] = "import ";
239-
if (memcmp(s_start, import_str, s_len) == 0) {
240-
*compl_str = import_str + s_len;
241-
return sizeof(import_str) - 1 - s_len;
242-
}
243-
}
244-
245-
return 0;
229+
q_last = q;
246230
}
231+
}
232+
}
247233

248-
// 1 match found, or multiple matches with a common prefix
249-
if (q_first == q_last || match_len > s_len) {
250-
*compl_str = match_str + s_len;
251-
return match_len - s_len;
234+
// nothing found
235+
if (q_first == 0) {
236+
if (s_len == 0) {
237+
*compl_str = " ";
238+
return 4;
239+
}
240+
// If there're no better alternatives, and if it's first word
241+
// in the line, try to complete "import".
242+
if (s_start == org_str) {
243+
static const char import_str[] = "import ";
244+
if (memcmp(s_start, import_str, s_len) == 0) {
245+
*compl_str = import_str + s_len;
246+
return sizeof(import_str) - 1 - s_len;
252247
}
248+
}
253249

254-
// multiple matches found, print them out
250+
return 0;
251+
}
255252

256-
#define WORD_SLOT_LEN (16)
257-
#define MAX_LINE_LEN (4 * WORD_SLOT_LEN)
253+
// 1 match found, or multiple matches with a common prefix
254+
if (q_first == q_last || match_len > s_len) {
255+
*compl_str = match_str + s_len;
256+
return match_len - s_len;
257+
}
258258

259-
int line_len = MAX_LINE_LEN; // force a newline for first word
260-
for (qstr q = q_first; q <= q_last; ++q) {
261-
size_t d_len;
262-
const char *d_str = (const char *)qstr_data(q, &d_len);
263-
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
264-
mp_load_method_protected(obj, q, dest, true);
265-
if (dest[0] != MP_OBJ_NULL) {
266-
int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len;
267-
if (gap < 2) {
268-
gap += WORD_SLOT_LEN;
269-
}
270-
if (line_len + gap + d_len <= MAX_LINE_LEN) {
271-
// TODO optimise printing of gap?
272-
for (int j = 0; j < gap; ++j) {
273-
mp_print_str(print, " ");
274-
}
275-
mp_print_str(print, d_str);
276-
line_len += gap + d_len;
277-
} else {
278-
mp_printf(print, "\n%s", d_str);
279-
line_len = d_len;
280-
}
259+
// multiple matches found, print them out
260+
261+
#define WORD_SLOT_LEN (16)
262+
#define MAX_LINE_LEN (4 * WORD_SLOT_LEN)
263+
264+
int line_len = MAX_LINE_LEN; // force a newline for first word
265+
for (qstr q = q_first; q <= q_last; ++q) {
266+
size_t d_len;
267+
const char *d_str = (const char *)qstr_data(q, &d_len);
268+
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
269+
mp_load_method_protected(obj, q, dest, true);
270+
if (dest[0] != MP_OBJ_NULL) {
271+
int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len;
272+
if (gap < 2) {
273+
gap += WORD_SLOT_LEN;
274+
}
275+
if (line_len + gap + d_len <= MAX_LINE_LEN) {
276+
// TODO optimise printing of gap?
277+
for (int j = 0; j < gap; ++j) {
278+
mp_print_str(print, " ");
281279
}
280+
mp_print_str(print, d_str);
281+
line_len += gap + d_len;
282+
} else {
283+
mp_printf(print, "\n%s", d_str);
284+
line_len = d_len;
282285
}
283286
}
284-
mp_print_str(print, "\n");
285-
286-
return (size_t)(-1); // indicate many matches
287287
}
288288
}
289+
mp_print_str(print, "\n");
290+
291+
return (size_t)(-1); // indicate many matches
289292
}
290293

291294
#endif // MICROPY_HELPER_REPL

0 commit comments

Comments
 (0)