Skip to content
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

Merged
merged 6 commits into from Aug 5, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions libr/cons/cons.c
Expand Up @@ -511,7 +511,7 @@ R_API void r_cons_fill_line() {
R_API void r_cons_clear_line(int std_err) {
#if __WINDOWS__
if (I.ansicon) {
fprintf (std_err? stderr: stdout,"\x1b[0K\r");
fprintf (std_err? stderr: stdout,"%s", ANSI_ESC_CLEAR_LINE);
} else {
char white[1024];
memset (&white, ' ', sizeof (white));
Expand All @@ -525,7 +525,7 @@ R_API void r_cons_clear_line(int std_err) {
fprintf (std_err? stderr: stdout, "\r%s\r", white);
}
#else
fprintf (std_err? stderr: stdout,"\x1b[0K\r");
fprintf (std_err? stderr: stdout,"%s", ANSI_ESC_CLEAR_LINE);
#endif
fflush (std_err? stderr: stdout);
}
Expand Down
198 changes: 185 additions & 13 deletions libr/cons/dietline.c
Expand Up @@ -442,7 +442,114 @@ 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 ? cons->pal.widget_bg : Color_INVERT;
char *selected_color = cons->color ? cons->pal.widget_sel : Color_INVERT_RESET;
bool scrollbar = sel_widget->options_len > R_SELWIDGET_MAXH;
int scrollbar_y = 0, scrollbar_l = 0;
if (scrollbar) {
scrollbar_y = (R_SELWIDGET_MAXH * (sel_widget->selection - sel_widget->scroll)) / sel_widget->options_len;
scrollbar_l = (R_SELWIDGET_MAXH * R_SELWIDGET_MAXH) / sel_widget->options_len;
}

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_strcat (background_color);
r_cons_printf ("%s", R_BETWEEN (scrollbar_y, y, scrollbar_y + scrollbar_l) ? SELWIDGET_SCROLLCHAR : " ");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SELWIDGET_SCROLLCHAR is utf8, you must set a var at the begining of the function to be that one or an ascii alternative when utf8 is not set

} else {
r_cons_memcat (" ", 1);
}
}

r_cons_gotoxy (pos_x + I.buffer.length, pos_y);
r_cons_memcat (Color_RESET_BG, 5);
r_cons_flush ();
}

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The 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) {
I.buffer.length = R_MIN (strlen (sel_widget->options[sel_widget->selection]), R_LINE_BUFSIZE - 1);
memcpy (I.buffer.data, sel_widget->options[sel_widget->selection], I.buffer.length);
I.buffer.data[I.buffer.length] = '\0';
I.buffer.index = I.buffer.length;
selection_widget_erase ();
}
}

static void selection_widget_update() {
if (I.completion.argc == 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;
Expand All @@ -456,6 +563,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
Expand Down Expand Up @@ -530,6 +642,14 @@ R_API void r_line_autocomplete() {
}
}

if (I.offset_prompt || I.file_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;
Expand Down Expand Up @@ -575,6 +695,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';
Expand All @@ -597,7 +718,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);
Expand Down Expand Up @@ -632,7 +753,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 ();
Expand All @@ -644,7 +768,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--;
}
Expand Down Expand Up @@ -831,7 +958,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--;
}
Expand All @@ -840,7 +970,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 ();
Expand Down Expand Up @@ -874,10 +1007,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';
Expand Down Expand Up @@ -905,6 +1045,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) {
Expand All @@ -927,7 +1071,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);
Expand Down Expand Up @@ -956,6 +1100,8 @@ R_API const char *r_line_readline_cb_win(RLineReadCallback cb, void *user) {
fflush (stdout);
}

R_FREE (I.sel_widget);

// should be here or not?
if (!memcmp (I.buffer.data, "!history", 8)) {
r_line_hist_list ();
Expand All @@ -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';
Expand All @@ -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);
Expand Down Expand Up @@ -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--;
}
Expand All @@ -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 ();
Expand Down Expand 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--;
}
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -1557,6 +1727,8 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) {
fflush (stdout);
}

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') {
Expand Down