-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vim-like autocompletion in visual offset prompt #10912
Changes from 2 commits
7c89189
3d8d3a7
934e398
ec2bcc5
6589ba7
8d8ee06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -442,7 +442,112 @@ R_API int r_line_hist_chop(const char *file, int limit) { | |
return 0; | ||
} | ||
|
||
static void draw_selection_widget () { | ||
RCons *cons = r_cons_singleton (); | ||
RSelWidget *sel_widget = I.sel_widget; | ||
int y, pos_y = cons->rows, pos_x = r_str_ansi_len (I.prompt); | ||
|
||
for (y = 0; y < sel_widget->options_len; y++) { | ||
sel_widget->w = R_MAX (sel_widget->w, strlen (sel_widget->options[y])); | ||
} | ||
sel_widget->w = R_MIN (sel_widget->w, R_SELWIDGET_MAXW); | ||
|
||
char *background_color = cons->color ? "\x1b[40m" : Color_INVERT; // XXX colors from palette | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dont hardcode ansi escapes. Use the Color_ macros |
||
char *selected_color = cons->color ? "\x1b[41m" : Color_INVERT_RESET; // XXX colors from palette | ||
bool scrollbar = sel_widget->options_len > R_SELWIDGET_MAXH; | ||
int scrollbar_y = scrollbar | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be clearer to just do:
|
||
? (R_SELWIDGET_MAXH * (sel_widget->selection - sel_widget->scroll)) / sel_widget->options_len | ||
: 0; | ||
int scrollbar_l = scrollbar | ||
? (R_SELWIDGET_MAXH * R_SELWIDGET_MAXH) / sel_widget->options_len | ||
: 0; | ||
|
||
for (y = 0; y < R_MIN (sel_widget->h, R_SELWIDGET_MAXH); y++) { | ||
r_cons_gotoxy (pos_x + 1, pos_y - y - 1); | ||
int scroll = R_MAX (0, sel_widget->selection - sel_widget->scroll); | ||
char *option = y < sel_widget->options_len ? sel_widget->options[y + scroll] : ""; | ||
r_cons_printf ("%s", sel_widget->selection == y + scroll ? selected_color : background_color); | ||
r_cons_printf ("%-*.*s", sel_widget->w, sel_widget->w, option); | ||
if (scrollbar) { | ||
r_cons_printf ("%s", background_color); | ||
r_cons_printf ("%s", R_BETWEEN(scrollbar_y, y, scrollbar_y + scrollbar_l) ? "█" : " "); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this character in define. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing space before ( |
||
} | ||
} | ||
|
||
r_cons_gotoxy (pos_x + I.buffer.length, pos_y); | ||
r_cons_printf ("%s", Color_RESET_BG); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use rcons.memcat, no need to format a %s |
||
r_cons_flush(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing space |
||
} | ||
|
||
static void selection_widget_up () { | ||
RSelWidget *sel_widget = I.sel_widget; | ||
if (sel_widget && sel_widget->selection < sel_widget->options_len - 1) { | ||
sel_widget->selection++; | ||
sel_widget->scroll = R_MIN (sel_widget->scroll + 1, R_SELWIDGET_MAXH - 1); | ||
} | ||
} | ||
|
||
static void selection_widget_down () { | ||
RSelWidget *sel_widget = I.sel_widget; | ||
if (sel_widget && sel_widget->selection > 0) { | ||
sel_widget->selection--; | ||
sel_widget->scroll = R_MAX (sel_widget->scroll - 1, 0); | ||
} | ||
} | ||
|
||
static void print_rline_task (void *core) { | ||
r_cons_clear_line (0); | ||
r_cons_printf ("%s%s%s", Color_RESET, I.prompt, I.buffer.data); | ||
r_cons_flush (); | ||
} | ||
|
||
static void selection_widget_erase () { | ||
RSelWidget *sel_widget = I.sel_widget; | ||
if (sel_widget) { | ||
sel_widget->options_len = 0; | ||
sel_widget->selection = -1; | ||
draw_selection_widget (); | ||
R_FREE(I.sel_widget); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing space |
||
RCons *cons = r_cons_singleton (); | ||
if (cons->event_resize && cons->event_data) { | ||
cons->event_resize (cons->event_data); | ||
cons->cb_task_oneshot (cons->user, print_rline_task, NULL); | ||
} | ||
} | ||
} | ||
|
||
static void selection_widget_select () { | ||
RSelWidget *sel_widget = I.sel_widget; | ||
if (sel_widget && sel_widget->selection < sel_widget->options_len) { | ||
strncpy (I.buffer.data, sel_widget->options[sel_widget->selection], R_LINE_BUFSIZE - 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strncpy and strlen? Thats innefficient |
||
I.buffer.length = strlen (I.buffer.data); | ||
I.buffer.index = I.buffer.length; | ||
selection_widget_erase (); | ||
} | ||
} | ||
|
||
static void selection_widget_update () { | ||
if (I.completion.argc == 0 || I.buffer.length == 0 || | ||
(I.completion.argc == 1 && I.buffer.length >= strlen (I.completion.argv[0]))) { | ||
selection_widget_erase (); | ||
return; | ||
} | ||
if (!I.sel_widget) { | ||
RSelWidget *sel_widget = R_NEW0 (RSelWidget); | ||
I.sel_widget = sel_widget; | ||
} | ||
I.sel_widget->scroll = 0; | ||
I.sel_widget->selection = 0; | ||
I.sel_widget->options_len = I.completion.argc; | ||
I.sel_widget->options = I.completion.argv; | ||
I.sel_widget->h = R_MAX (I.sel_widget->h, I.completion.argc); | ||
draw_selection_widget (); | ||
r_cons_flush (); | ||
return; | ||
} | ||
|
||
R_API void r_line_autocomplete() { | ||
|
||
int argc = 0; | ||
char *p; | ||
const char **argv = NULL; | ||
|
@@ -456,6 +561,11 @@ R_API void r_line_autocomplete() { | |
argv = I.completion.argv; | ||
} | ||
|
||
if (I.sel_widget && !I.sel_widget->complete_common) { | ||
selection_widget_update (); | ||
return; | ||
} | ||
|
||
p = (char *) r_sub_str_lchr (I.buffer.data, 0, I.buffer.index, ' '); | ||
if (!p) { | ||
p = (char *) r_sub_str_lchr (I.buffer.data, 0, I.buffer.index, '@'); // HACK FOR r2 | ||
|
@@ -530,6 +640,14 @@ R_API void r_line_autocomplete() { | |
} | ||
} | ||
|
||
if (I.offset_prompt) { | ||
selection_widget_update (); | ||
if (I.sel_widget) { | ||
I.sel_widget->complete_common = false; | ||
} | ||
return; | ||
} | ||
|
||
/* show options */ | ||
if (opt > 1 && I.echo) { | ||
const int sep = 3; | ||
|
@@ -575,6 +693,7 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
char *tmp_ed_cmd, prev = 0; | ||
HANDLE hClipBoard; | ||
char *clipText; | ||
int prev_buflen = 0; | ||
|
||
I.buffer.index = I.buffer.length = 0; | ||
I.buffer.data[0] = '\0'; | ||
|
@@ -597,7 +716,7 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
|
||
if (I.echo) { | ||
r_cons_clear_line (0); | ||
printf ("\x1b[0K\r%s%s", I.prompt, I.buffer.data); | ||
printf ("%s%s%s", Color_RESET, I.prompt, I.buffer.data); | ||
fflush (stdout); | ||
} | ||
r_cons_break_push (NULL, NULL); | ||
|
@@ -632,7 +751,10 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
I.buffer.index = I.buffer.index? I.buffer.index - 1: 0; | ||
break; | ||
case 38: // up arrow | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_up (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
gcomp_idx++; | ||
} else if (r_line_hist_up () == -1) { | ||
r_cons_break_pop (); | ||
|
@@ -644,7 +766,10 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
I.buffer.index + 1: I.buffer.length; | ||
break; | ||
case 40:// down arrow | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_up (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
if (gcomp_idx > 0) { | ||
gcomp_idx--; | ||
} | ||
|
@@ -831,7 +956,10 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
paste (); | ||
break; | ||
case 14:// ^n | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_down (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
if (gcomp_idx > 0) { | ||
gcomp_idx--; | ||
} | ||
|
@@ -840,7 +968,10 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
} | ||
break; | ||
case 16:// ^p | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_down (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
gcomp_idx++; | ||
} else { | ||
r_line_hist_up (); | ||
|
@@ -874,10 +1005,17 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
break; | ||
/* tab */ | ||
case 9: // tab | ||
if (I.sel_widget) { | ||
I.sel_widget->complete_common = true; | ||
} | ||
r_line_autocomplete (); | ||
break; | ||
/* enter */ | ||
case 13: | ||
if (I.sel_widget) { | ||
selection_widget_select (); | ||
break; | ||
} | ||
if (gcomp && I.buffer.length > 0) { | ||
strncpy (I.buffer.data, gcomp_line, R_LINE_BUFSIZE - 1); | ||
I.buffer.data[R_LINE_BUFSIZE - 1] = '\0'; | ||
|
@@ -905,6 +1043,10 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
I.buffer.index++; | ||
break; | ||
} | ||
if (I.sel_widget && I.buffer.length != prev_buflen) { | ||
prev_buflen = I.buffer.length; | ||
r_line_autocomplete (); | ||
} | ||
prev = buf[0]; | ||
if (I.echo) { | ||
if (gcomp) { | ||
|
@@ -927,7 +1069,7 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
int chars = R_MAX (1, strlen (I.buffer.data)); // wtf? | ||
int len, cols = R_MAX (1, columns - r_str_ansi_len (I.prompt) - 2); | ||
/* print line */ | ||
printf ("\r%s", I.prompt); | ||
printf ("\r%s%s", Color_RESET, I.prompt); | ||
fwrite (I.buffer.data, 1, R_MIN (cols, chars), stdout); | ||
/* place cursor */ | ||
printf ("\r%s", I.prompt); | ||
|
@@ -956,6 +1098,10 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) { | |
fflush (stdout); | ||
} | ||
|
||
if (I.sel_widget) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to check for NULL in free-like functions |
||
R_FREE (I.sel_widget); | ||
} | ||
|
||
// should be here or not? | ||
if (!memcmp (I.buffer.data, "!history", 8)) { | ||
r_line_hist_list (); | ||
|
@@ -980,6 +1126,7 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
#endif | ||
int ch, i = 0; /* grep completion */ | ||
char *tmp_ed_cmd, prev = 0; | ||
int prev_buflen = -1; | ||
|
||
I.buffer.index = I.buffer.length = 0; | ||
I.buffer.data[0] = '\0'; | ||
|
@@ -1002,7 +1149,7 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
|
||
if (I.echo) { | ||
r_cons_clear_line (0); | ||
printf ("\x1b[0K\r%s%s", I.prompt, I.buffer.data); | ||
printf ("%s%s%s", Color_RESET, I.prompt, I.buffer.data); | ||
fflush (stdout); | ||
} | ||
r_cons_break_push (NULL, NULL); | ||
|
@@ -1196,7 +1343,10 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
paste (); | ||
break; | ||
case 14:// ^n | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_down (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
if (gcomp_idx > 0) { | ||
gcomp_idx--; | ||
} | ||
|
@@ -1205,7 +1355,10 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
} | ||
break; | ||
case 16:// ^p | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_up (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
gcomp_idx++; | ||
} else { | ||
r_line_hist_up (); | ||
|
@@ -1278,15 +1431,21 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
break; | ||
/* arrows */ | ||
case 'A': // up arrow | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_up (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
gcomp_idx++; | ||
} else if (r_line_hist_up () == -1) { | ||
r_cons_break_pop (); | ||
return NULL; | ||
} | ||
break; | ||
case 'B': // down arrow | ||
if (gcomp) { | ||
if (I.sel_widget) { | ||
selection_widget_down (); | ||
draw_selection_widget (); | ||
} else if (gcomp) { | ||
if (gcomp_idx > 0) { | ||
gcomp_idx--; | ||
} | ||
|
@@ -1450,9 +1609,16 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
I.buffer.length++; | ||
I.buffer.index++; | ||
} | ||
if (I.sel_widget) { | ||
I.sel_widget->complete_common = true; | ||
} | ||
r_line_autocomplete (); | ||
break; | ||
case 13: | ||
case 13: // enter | ||
if (I.sel_widget) { | ||
selection_widget_select (); | ||
break; | ||
} | ||
if (gcomp && I.buffer.length > 0) { | ||
strncpy (I.buffer.data, gcomp_line, R_LINE_BUFSIZE - 1); | ||
I.buffer.data[R_LINE_BUFSIZE - 1] = '\0'; | ||
|
@@ -1506,6 +1672,10 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
#endif | ||
break; | ||
} | ||
if (I.sel_widget && I.buffer.length != prev_buflen) { | ||
prev_buflen = I.buffer.length; | ||
r_line_autocomplete (); | ||
} | ||
prev = buf[0]; | ||
if (I.echo) { | ||
if (gcomp) { | ||
|
@@ -1528,7 +1698,7 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
int chars = R_MAX (1, strlen (I.buffer.data)); // wtf? | ||
int len, cols = R_MAX (1, columns - r_str_ansi_len (I.prompt) - 2); | ||
/* print line */ | ||
printf ("\r%s", I.prompt); | ||
printf ("\r%s%s", Color_RESET, I.prompt); | ||
fwrite (I.buffer.data, 1, R_MIN (cols, chars), stdout); | ||
/* place cursor */ | ||
printf ("\r%s", I.prompt); | ||
|
@@ -1557,6 +1727,10 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) { | |
fflush (stdout); | ||
} | ||
|
||
if (I.sel_widget) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to check for null before using |
||
R_FREE (I.sel_widget); | ||
} | ||
|
||
// should be here or not? | ||
if (!memcmp (I.buffer.data, "!history", 8)) { | ||
// if (I.buffer.data[0]=='!' && I.buffer.data[1]=='\0') { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all these functions, according to the style, should have
(
without a space before it.