Improve completion system

- rename and extend CompletionEntry as CompletionDef
- create xxx_completion CompletionDef structures
- rename xxx_completion() functions to xxx_complete()
- register CompletionDef structs with qe_register_completion()
- add (start, end) range in CompleteState
- use eb_puts() and eb_putc() instead of eb_printf()
- simplify eb_delete_chars()
- ignore left pane in compare-windows()
- simplify qe_list_bindings()
- improve command and variable completion popup
This commit is contained in:
Charlie Gordon 2020-10-17 15:41:31 +00:00
commit 9d967ad29c
15 changed files with 371 additions and 158 deletions

View file

@ -152,11 +152,10 @@ static void build_bufed_list(BufedState *bs, EditState *s)
b->cur_style = BUFED_STYLE_DIRECTORY;
else
b->cur_style = BUFED_STYLE_FILENAME;
eb_printf(b, "%s",
make_user_path(path, sizeof(path), b1->filename));
eb_puts(b, make_user_path(path, sizeof(path), b1->filename));
b->cur_style = style0;
}
eb_printf(b, "\n");
eb_putc(b, '\n');
}
b->modified = 0;
b->flags |= BF_READONLY;

View file

@ -1531,16 +1531,7 @@ int eb_delete_uchar(EditBuffer *b, int offset)
*/
int eb_delete_chars(EditBuffer *b, int offset, int n)
{
int offset1 = eb_skip_chars(b, offset, n);
int size = offset1 - offset;
if (size < 0) {
offset += size;
offset1 -= size;
size = -size;
}
return eb_delete(b, offset, size);
return eb_delete_range(b, offset, eb_skip_chars(b, offset, n));
}
/* XXX: only stateless charsets are supported */

View file

@ -1130,7 +1130,7 @@ void qe_register_charset(struct QECharset *charset)
*pp = charset;
}
void charset_completion(CompleteState *cp)
void charset_complete(CompleteState *cp)
{
QECharset *charset;
char name[32];

14
dired.c
View file

@ -683,11 +683,11 @@ static void dired_update_buffer(DiredState *ds, EditBuffer *b, EditState *s,
if (DIRED_HEADER) {
int seq = ' ';
b->cur_style = DIRED_STYLE_HEADER;
eb_printf(b, " Directory of ");
eb_puts(b, " Directory of ");
b->cur_style = DIRED_STYLE_DIRECTORY;
eb_printf(b, "%s", ds->path);
eb_puts(b, ds->path);
b->cur_style = DIRED_STYLE_HEADER;
eb_printf(b, "\n ");
eb_puts(b, "\n ");
if (ds->ndirs) {
eb_printf(b, "%c %d %s", seq, ds->ndirs,
inflect(ds->ndirs, "directory", "directories"));
@ -717,7 +717,7 @@ static void dired_update_buffer(DiredState *ds, EditBuffer *b, EditState *s,
if (ds->ndirs + ds->ndirs_hidden + ds->nfiles + ds->nfiles_hidden == 0) {
eb_printf(b, "%c empty", seq);
}
eb_printf(b, "\n");
eb_putc(b, '\n');
}
b->cur_style = DIRED_STYLE_NORMAL;
@ -767,12 +767,12 @@ static void dired_update_buffer(DiredState *ds, EditBuffer *b, EditState *s,
else
b->cur_style = DIRED_STYLE_FILENAME;
eb_printf(b, "%s", dip->name);
eb_puts(b, dip->name);
if (1) {
int trailchar = get_trailchar(dip->mode);
if (trailchar) {
eb_printf(b, "%c", trailchar);
eb_putc(b, trailchar);
}
}
if (S_ISLNK(dip->mode)
@ -780,7 +780,7 @@ static void dired_update_buffer(DiredState *ds, EditBuffer *b, EditState *s,
eb_printf(b, " -> %s", buf);
}
b->cur_style = DIRED_STYLE_NORMAL;
eb_printf(b, "\n");
eb_putc(b, '\n');
}
b->modified = 0;
b->flags |= BF_READONLY;

View file

@ -123,21 +123,24 @@ void do_compare_windows(EditState *s, int argval)
s1 = s;
/* Should use same internal function as for next_window */
if (s1->next_window)
s2 = s1->next_window;
else
s2 = qs->first_window;
for (s2 = s1;;) {
s2 = s2->next_window;
if (s2 == NULL)
s2 = qs->first_window;
if (s2 == s1) {
/* single window: bail out */
return;
}
if (s2->b->flags & BF_DIRED)
continue;
break;
}
if (argval != NO_ARG) {
if (argval & 4)
qs->ignore_spaces ^= 1;
if (argval & 16)
qs->ignore_comments ^= 1;
}
if (s1 == s2) {
/* single window: bail out */
return;
}
size1 = s1->b->total_size;
size2 = s2->b->total_size;
@ -867,8 +870,7 @@ static void do_unset_key(EditState *s, const char *keystr, int local)
/*---------------- help ----------------*/
static int qe_list_bindings(char *buf, int size, CmdDef *d,
ModeDef *mode, int inherit)
int qe_list_bindings(CmdDef *d, ModeDef *mode, int inherit, char *buf, int size)
{
int pos;
buf_t outbuf, *out;
@ -904,7 +906,7 @@ void do_show_bindings(EditState *s, const char *cmd_name)
put_status(s, "No command %s", cmd_name);
return;
}
if (qe_list_bindings(buf, sizeof(buf), d, s->mode, 1)) {
if (qe_list_bindings(d, s->mode, 1, buf, sizeof(buf))) {
put_status(s, "%s is bound to %s", cmd_name, buf);
} else {
put_status(s, "%s is not bound to any key", cmd_name);
@ -916,18 +918,21 @@ static void print_bindings(EditBuffer *b, ModeDef *mode)
char buf[256];
CmdDef *d;
int gfound;
//int start = b->total_size;
/* XXX: should sort matches */
gfound = 0;
d = qe_state.first_cmd;
while (d != NULL) {
while (d->name != NULL) {
if (qe_list_bindings(buf, sizeof(buf), d, mode, 0)) {
if (qe_list_bindings(d, mode, 0, buf, sizeof(buf))) {
if (!gfound) {
if (mode) {
eb_printf(b, "\n%s mode bindings:\n\n", mode->name);
} else {
eb_printf(b, "\nGlobal bindings:\n\n");
}
//start = b->total_size;
gfound = 1;
}
eb_printf(b, "%24s : %s\n", d->name, buf);
@ -936,6 +941,7 @@ static void print_bindings(EditBuffer *b, ModeDef *mode)
}
d = d->action.next;
}
//do_sort_span(b, start, b->total_size, 0, NO_ARG);
}
void do_describe_bindings(EditState *s)
@ -966,7 +972,10 @@ void do_apropos(EditState *s, const char *str)
if (!b)
return;
eb_printf(b, "\n");
eb_putc(b, '\n');
/* XXX: should sort matches */
/* XXX: should print description */
found = 0;
d = qs->first_cmd;
@ -975,12 +984,12 @@ void do_apropos(EditState *s, const char *str)
if (strstr(d->name, str)) {
/* print name and prototype */
qe_get_prototype(d, buf, sizeof(buf));
eb_printf(b, "command: %s(%s)", d->name, buf);
if (qe_list_bindings(buf, sizeof(buf), d, s->mode, 1))
eb_printf(b, "command: %s%s", d->name, buf);
if (qe_list_bindings(d, s->mode, 1, buf, sizeof(buf)))
eb_printf(b, " bound to %s", buf);
eb_printf(b, "\n");
eb_putc(b, '\n');
/* TODO: print short description */
eb_printf(b, "\n");
eb_putc(b, '\n');
found = 1;
}
d++;
@ -994,7 +1003,7 @@ void do_apropos(EditState *s, const char *str)
eb_printf(b, "%s variable: %s -> %s\n",
var_domain[vp->domain], vp->name, buf);
/* TODO: print short description */
eb_printf(b, "\n");
eb_putc(b, '\n');
found = 1;
}
}
@ -1023,7 +1032,7 @@ static void do_about_qemacs(EditState *s)
b = eb_scratch("*About QEmacs*", BF_UTF8);
eb_printf(b, "\n %s\n\n%s\n", str_version, str_credits);
/* list commands */
/* list current bindings */
print_bindings(b, s->mode);
print_bindings(b, NULL);
@ -1035,11 +1044,13 @@ static void do_about_qemacs(EditState *s)
/* list commands */
eb_printf(b, "\nCommands:\n\n");
/* XXX: should sort commands */
d = qs->first_cmd;
while (d != NULL) {
while (d->name != NULL) {
qe_get_prototype(d, buf, sizeof(buf));
eb_printf(b, " %s(%s);\n", d->name, buf);
eb_printf(b, " %s%s\n", d->name, buf);
d++;
}
d = d->action.next;
@ -1052,6 +1063,7 @@ static void do_about_qemacs(EditState *s)
char **envp;
eb_printf(b, "\nEnvironment:\n\n");
/* XXX: should sort environment variables */
for (envp = environ; *envp; envp++) {
eb_printf(b, " %s\n", *envp);
}
@ -1226,7 +1238,7 @@ static void do_describe_buffer(EditState *s, int argval)
if (!b1)
return;
eb_printf(b1, "\n");
eb_putc(b1, '\n');
eb_printf(b1, " name: %s\n", b->name);
eb_printf(b1, " filename: %s\n", b->filename);
@ -1370,12 +1382,12 @@ static void do_describe_buffer(EditState *s, int argval)
col += eb_printf(b1, " 0x%02x", i);
if (col >= 60) {
eb_printf(b1, "\n");
eb_putc(b1, '\n');
col = 0;
}
}
if (col) {
eb_printf(b1, "\n");
eb_putc(b1, '\n');
}
}
@ -1402,14 +1414,14 @@ static void do_describe_buffer(EditState *s, int argval)
if (c < 32 || c >= 127)
eb_printf(b1, "\\%03o", c);
else
eb_printf(b1, "%c", c);
eb_putc(b1, c);
continue;
}
eb_printf(b1, "\\%c", c);
}
eb_printf(b1, "|%s\n", p->size > 16 ? "..." : "");
}
eb_printf(b1, "\n");
eb_putc(b1, '\n');
}
b1->flags |= BF_READONLY;
@ -1425,7 +1437,7 @@ static void do_describe_window(EditState *s, int argval)
if (!b1)
return;
eb_printf(b1, "\n");
eb_putc(b1, '\n');
w = 28;
eb_printf(b1, "%*s: %d, %d\n", w, "xleft, ytop", s->xleft, s->ytop);
@ -1479,7 +1491,7 @@ static void do_describe_window(EditState *s, int argval)
eb_printf(b1, "%*s: %d\n", w, "show_selection", s->show_selection);
eb_printf(b1, "%*s: %d\n", w, "region_style", s->region_style);
eb_printf(b1, "%*s: %d\n", w, "curline_style", s->curline_style);
eb_printf(b1, "\n");
eb_putc(b1, '\n');
b1->flags |= BF_READONLY;
show_popup(s, b1, "Window Description");
@ -1495,7 +1507,7 @@ static void do_describe_screen(EditState *e, int argval)
if (!b1)
return;
eb_printf(b1, "\n");
eb_putc(b1, '\n');
w = 16;
eb_printf(b1, "%*s: %s\n", w, "dpy.name", s->dpy.name);
@ -1627,6 +1639,8 @@ static void do_sort_span(EditState *s, int p1, int p2, int flags, int argval) {
struct chunk *chunk_array;
s->region_style = 0;
if (argval != NO_ARG)
flags |= argval;
if (p1 > p2) {
int tmp = p1;
@ -1634,8 +1648,6 @@ static void do_sort_span(EditState *s, int p1, int p2, int flags, int argval) {
p2 = tmp;
}
ctx.b = s->b;
if (argval != NO_ARG)
flags |= argval;
ctx.flags = flags;
ctx.col = 0;
eb_get_pos(s->b, &line1, &col1, p1); /* line1 is included */
@ -1703,7 +1715,7 @@ static void tag_buffer(EditState *s) {
}
}
static void tag_completion(CompleteState *cp) {
static void tag_complete(CompleteState *cp) {
/* XXX: only support current buffer */
QEProperty *p;
@ -1876,6 +1888,10 @@ static CmdDef extra_commands[] = {
CMD_DEF_END,
};
static CompletionDef tag_completion = {
"tag", tag_complete,
};
static int extras_init(void)
{
int key;
@ -1884,7 +1900,7 @@ static int extras_init(void)
for (key = KEY_META('0'); key <= KEY_META('9'); key++) {
qe_register_binding(key, "numeric-argument", NULL);
}
register_completion("tag", tag_completion);
qe_register_completion(&tag_completion);
return 0;
}

10
image.c
View file

@ -846,7 +846,7 @@ void image_mode_line(EditState *s, buf_t *out)
ib->interleaved ? 'I' : ' ');
}
static void pixel_format_completion(CompleteState *cp)
static void pixel_format_complete(CompleteState *cp)
{
int i;
const char *name;
@ -863,7 +863,7 @@ static CmdDef image_commands[] = {
"image-rotate", image_rotate)
CMD2( 'c', KEY_NONE,
"image-convert", image_convert, ESs,
"s{New pixel format: }[pixel_format]|pixel_format|")
"s{New pixel format: }[pixel-format]|pixel-format|")
CMD2( 'b', KEY_NONE,
"image-set-background-color", image_set_background_color, ESs,
"s{Background color (use 'transparent' for tiling): }")
@ -909,13 +909,17 @@ static ModeDef image_mode = {
.get_mode_line = image_mode_line,
};
static CompletionDef pixel_format_completion = {
"pixel-format", pixel_format_complete
};
static int image_init(void)
{
av_register_all();
eb_register_data_type(&image_data_type);
qe_register_mode(&image_mode, MODEF_DATATYPE | MODEF_VIEW);
qe_register_cmd_table(image_commands, &image_mode);
register_completion("pixel_format", pixel_format_completion);
qe_register_completion(&pixel_format_completion);
/* additional mode specific keys */
qe_register_binding('f', "toggle-full-screen", &image_mode);
return 0;

View file

@ -80,7 +80,7 @@ void register_input_method(InputMethod *m)
*p = m;
}
static void input_completion(CompleteState *cp)
static void input_complete(CompleteState *cp)
{
QEmacsState *qs = cp->s->qe_state;
InputMethod *m;
@ -122,9 +122,13 @@ void do_switch_input_method(EditState *s)
s->input_method = s->selected_input_method;
}
static CompletionDef input_completion = {
"input", input_complete,
};
void init_input_methods(void)
{
register_input_method(&default_input_method);
register_input_method(&unicode_input_method);
register_completion("input", input_completion);
qe_register_completion(&input_completion);
}

View file

@ -211,7 +211,7 @@ static struct latex_function {
#undef INIT_TAIL
};
static void latex_completion(CompleteState *cp)
static void latex_complete(CompleteState *cp)
{
struct latex_function *func;
@ -344,12 +344,16 @@ static ModeDef texinfo_mode = {
.colorize_flags = TEX_TEXINFO,
};
static CompletionDef latex_completion = {
"latex", latex_complete,
};
static int latex_init(void)
{
qe_register_mode(&latex_mode, MODEF_SYNTAX);
qe_register_mode(&texinfo_mode, MODEF_SYNTAX);
qe_register_cmd_table(latex_commands, &latex_mode);
register_completion("latex", latex_completion);
qe_register_completion(&latex_completion);
return 0;
}

264
qe.c
View file

@ -62,7 +62,6 @@ static void display1(DisplayState *ds);
#ifndef CONFIG_TINY
static void save_selection(void);
#endif
static CompletionFunc find_completion(const char *name);
QEmacsState qe_state;
/* should handle multiple screens, and multiple sessions */
@ -206,7 +205,7 @@ void qe_register_mode(ModeDef *m, int flags)
}
}
void mode_completion(CompleteState *cp)
void mode_complete(CompleteState *cp)
{
QEmacsState *qs = cp->s->qe_state;
ModeDef *m;
@ -218,6 +217,10 @@ void mode_completion(CompleteState *cp)
}
}
static CompletionDef mode_completion = {
"mode", mode_complete
};
/* commands handling */
CmdDef *qe_find_cmd(const char *cmd_name)
@ -237,7 +240,7 @@ CmdDef *qe_find_cmd(const char *cmd_name)
return NULL;
}
void command_completion(CompleteState *cp)
void command_complete(CompleteState *cp)
{
QEmacsState *qs = cp->s->qe_state;
CmdDef *d;
@ -252,6 +255,51 @@ void command_completion(CompleteState *cp)
}
}
int command_print_entry(EditState *s, const char *name)
{
EditBuffer *b = s->b;
CmdDef *d = qe_find_cmd(name);
if (d) {
char buf[256];
int len;
b->cur_style = QE_STYLE_FUNCTION;
len = eb_puts(b, d->name);
b->cur_style = QE_STYLE_DEFAULT;
qe_get_prototype(d, buf, sizeof buf);
len += eb_puts(b, buf);
#ifndef CONFIG_TINY
if (qe_list_bindings(d, s->mode, 1, buf, sizeof buf)) {
b->cur_style = QE_STYLE_COMMENT;
if (2 + len < 40) {
b->tab_width = max(2 + len, b->tab_width);
len += eb_putc(b, '\t');
} else {
b->tab_width = 40;
}
len += eb_printf(b, " bound to %s", buf);
b->cur_style = QE_STYLE_DEFAULT;
}
#endif
return len;
} else {
return eb_puts(b, name);
}
}
int command_get_entry(EditState *s, char *dest, int size, int offset)
{
int len;
eb_fgets(s->b, dest, size, offset, &offset);
len = strcspn(dest, " \t\n(");
dest[len] = '\0'; /* strip the TAB or trailing newline if any */
return len;
}
static CompletionDef command_completion = {
"command", command_complete, command_print_entry, command_get_entry
};
static int qe_register_binding1(unsigned int *keys, int nb_keys,
CmdDef *d, ModeDef *m)
{
@ -2958,7 +3006,7 @@ void get_style(EditState *e, QEStyleDef *stp, QETermStyle style)
apply_style(stp, style);
}
void style_completion(CompleteState *cp)
void style_complete(CompleteState *cp)
{
int i;
QEStyleDef *stp;
@ -2997,6 +3045,10 @@ QEStyleDef *find_style(const char *name)
return NULL;
}
static CompletionDef style_completion = {
"style", style_complete
};
static const char * const qe_style_properties[] = {
#define CSS_PROP_COLOR 0
"color", /* color */
@ -3015,7 +3067,7 @@ static const char * const qe_style_properties[] = {
"text-decoration", /* text_decoration: none / underline */
};
void style_property_completion(CompleteState *cp)
void style_property_complete(CompleteState *cp)
{
int i;
@ -3024,6 +3076,10 @@ void style_property_completion(CompleteState *cp)
}
}
static CompletionDef style_property_completion = {
"style-property", style_property_complete
};
int find_style_property(const char *name)
{
int i;
@ -4721,6 +4777,8 @@ int qe_get_prototype(CmdDef *d, char *buf, int size)
out = buf_init(&outbuf, buf, size);
buf_put_byte(out, '(');
/* construct argument type list */
r = d->name + strlen(d->name) + 1;
if (*r == '*') {
@ -4763,6 +4821,7 @@ int qe_get_prototype(CmdDef *d, char *buf, int size)
buf_puts(out, *history ? history : completion);
}
}
buf_put_byte(out, ')');
return out->len;
}
@ -4874,6 +4933,7 @@ static void parse_args(ExecCmdState *es)
char def_input[1024];
/* XXX: currently, default input is handled non generically */
/* XXX: should use completion function for default input? */
def_input[0] = '\0';
es->default_input[0] = '\0';
if (strequal(completion_name, "file")) {
@ -5010,6 +5070,7 @@ void do_execute_command(EditState *s, const char *cmd, int argval)
{
CmdDef *d;
/* XXX: should test for '(' and '=' and evaluate script instead */
d = qe_find_cmd(cmd);
if (d) {
exec_command(s, d, argval, 0);
@ -5917,7 +5978,7 @@ static const char *file_completion_ignore_extensions = {
"|"
};
void file_completion(CompleteState *cp)
void file_complete(CompleteState *cp)
{
char path[MAX_FILENAME_SIZE];
char file[MAX_FILENAME_SIZE];
@ -5969,7 +6030,11 @@ void file_completion(CompleteState *cp)
find_file_close(&ffst);
}
void buffer_completion(CompleteState *cp)
static CompletionDef file_completion = {
"file", file_complete
};
void buffer_complete(CompleteState *cp)
{
QEmacsState *qs = cp->s->qe_state;
EditBuffer *b;
@ -5980,45 +6045,69 @@ void buffer_completion(CompleteState *cp)
}
}
/* register a new completion method */
void register_completion(const char *name, CompletionFunc completion_func)
{
QEmacsState *qs = &qe_state;
CompletionEntry **lp, *p;
static CompletionDef buffer_completion = {
"buffer", buffer_complete
};
p = qe_mallocz(CompletionEntry);
if (!p)
return;
p->name = name;
p->completion_func = completion_func;
p->next = NULL;
lp = &qs->first_completion;
while (*lp != NULL)
lp = &(*lp)->next;
*lp = p;
static int default_completion_window_print_entry(EditState *s, const char *name) {
return eb_puts(s->b, name);
}
static CompletionFunc find_completion(const char *name)
static int default_completion_window_get_entry(EditState *s, char *dest, int size, int offset) {
int len = eb_fgets(s->b, dest, size, offset, &offset);
char *p = strchr(dest, '\t');
if (p != NULL)
len = p - dest;
dest[len] = '\0'; /* strip the TAB or trailing newline if any */
return len;
}
/* register a new completion method */
void qe_register_completion(CompletionDef *cp)
{
CompletionEntry *p;
QEmacsState *qs = &qe_state;
CompletionDef **p;
for (p = &qs->first_completion;; p = &(*p)->next) {
if (*p == cp) {
/* completion is already registered, do nothing */
return;
}
if (*p == NULL) {
cp->next = NULL;
*p = cp;
break;
}
}
if (!cp->print_entry)
cp->print_entry = default_completion_window_print_entry;
if (!cp->get_entry)
cp->get_entry = default_completion_window_get_entry;
}
static CompletionDef *find_completion(const char *name)
{
CompletionDef *p;
if (name[0] != '\0') {
for (p = qe_state.first_completion; p != NULL; p = p->next) {
if (strequal(p->name, name))
return p->completion_func;
return p;
}
}
return NULL;
}
static void complete_start(CompleteState *cp, EditState *s, EditState *target)
static void complete_start(CompleteState *cp, EditState *s, int start, int end,
EditState *target)
{
memset(cp, 0, sizeof(*cp));
cp->s = s;
cp->target = target;
cp->len = eb_get_contents(s->b, cp->current, sizeof(cp->current));
cp->start = start;
cp->end = end;
cp->len = eb_get_region_contents(s->b, cp->start, cp->end,
cp->current, sizeof(cp->current));
}
/* XXX: should have a globbing option */
@ -6065,8 +6154,10 @@ typedef struct MinibufState {
void *opaque;
EditState *completion_popup_window; /* XXX: should have a popup_window member */
OWNED char *completion_name;
CompletionFunc completion_function;
int completion_flags;
int completion_start;
int completion_end;
CompletionDef *completion;
StringArray *history;
int history_index;
@ -6082,7 +6173,7 @@ static inline MinibufState *minibuffer_get_state(EditState *e, int status) {
void do_minibuffer_complete(EditState *s, int type)
{
QEmacsState *qs = s->qe_state;
int count, i, match_len, c;
int count, i, match_len, c, start, end;
CompleteState cs;
StringItem **outputs;
EditState *e;
@ -6093,7 +6184,7 @@ void do_minibuffer_complete(EditState *s, int type)
if ((mb = minibuffer_get_state(s, 1)) == NULL)
return;
if (!mb->completion_function)
if (!mb->completion)
return;
/* Remove highlighted selection. */
@ -6117,8 +6208,21 @@ void do_minibuffer_complete(EditState *s, int type)
return;
}
complete_start(&cs, s, s->target_window);
(*mb->completion_function)(&cs);
start = 0;
end = s->offset;
if (mb->completion_flags) {
/* XXX: completion select? */
int offset = end;
while ((start = offset) > 0) {
int c = eb_prevc(s->b, offset, &offset);
if (!qe_isalnum_(c) && c != '-')
break;
}
}
mb->completion_start = start;
mb->completion_end = end;
complete_start(&cs, s, start, end, s->target_window);
(*mb->completion->enumerate)(&cs);
count = cs.cs.nb_items;
outputs = cs.cs.items;
#if 0
@ -6150,10 +6254,12 @@ void do_minibuffer_complete(EditState *s, int type)
if (match_len > cs.len) {
/* add the possible chars */
// XXX: potential utf-8 issue?
eb_write(s->b, 0, outputs[0]->str, match_len);
s->offset = match_len;
// XXX: replace the completed part, not necessarily at the start (use mark?)
// XXX: should delete region and insert as utf-8
eb_replace(s->b, cs.start, cs.end - cs.start, outputs[0]->str, match_len);
s->offset = cs.start + match_len;
if (type == COMPLETION_OTHER) {
do_mark_region(s, match_len, cs.len);
do_mark_region(s, cs.start + match_len, cs.start + cs.len); // XXX: ???
}
} else {
if (count > 1) {
@ -6170,7 +6276,7 @@ void do_minibuffer_complete(EditState *s, int type)
w = (w1 * 3) / 4;
h = (h1 * 3) / 4;
e = edit_new(b, (w1 - w) / 2, (h1 - h) / 2, w, h, WF_POPUP);
snprintf(buf, sizeof buf, "Select a %s:", mb->completion_name);
snprintf(buf, sizeof buf, "Select a %s:", mb->completion->name);
e->caption = qe_strdup(buf);
e->target_window = s;
mb->completion_popup_window = e;
@ -6190,10 +6296,12 @@ void do_minibuffer_complete(EditState *s, int type)
qsort(outputs, count, sizeof(StringItem *), completion_sort_func);
b->flags &= ~BF_READONLY;
eb_delete(b, 0, b->total_size);
b->tab_width = 4;
for (i = 0; i < count; i++) {
eb_printf(b, " %s", outputs[i]->str);
eb_putc(b, ' '); /* XXX: should use window margins */
mb->completion->print_entry(e, outputs[i]->str);
if (i != count - 1)
eb_printf(b, "\n");
eb_putc(b, '\n');
}
b->flags |= BF_READONLY;
e->mouse_force_highlight = 1;
@ -6221,7 +6329,7 @@ void do_minibuffer_electric(EditState *s, int key)
int c, offset, stop;
MinibufState *mb = minibuffer_get_state(s, 0);
if (mb && mb->completion_function == file_completion) {
if (mb && mb->completion == &file_completion) {
stop = s->offset;
c = eb_prevc(s->b, s->offset, &offset);
if (c == '/') {
@ -6242,7 +6350,7 @@ void do_minibuffer_complete_space(EditState *s)
QEmacsState *qs = s->qe_state;
MinibufState *mb = minibuffer_get_state(s, 0);
if (!mb || !mb->completion_function) {
if (!mb || !mb->completion) {
do_char(s, ' ', 1);
} else
if (check_window(&mb->completion_popup_window)
@ -6278,15 +6386,15 @@ void minibuf_complete_scroll_up_down(qe__unused__ EditState *s, int dir)
}
}
static void minibuf_set_str(EditState *s, const char *str)
static void minibuf_set_str(EditState *s, int start, int end, const char *str)
{
int len;
eb_delete(s->b, 0, s->b->total_size);
/* Replace the completion trigger zone */
/* XXX: should insert utf-8? */
len = strlen(str);
eb_write(s->b, 0, str, len);
s->offset = len;
eb_replace(s->b, start, end - start, str, len);
s->offset = start + len;
}
/* CG: should use buffer of responses */
@ -6347,7 +6455,7 @@ void do_minibuffer_history(EditState *s, int dir)
/* insert history text */
mb->history_index = index;
str = hist->items[index]->str;
minibuf_set_str(s, str);
minibuf_set_str(s, 0, s->b->total_size, str);
if (index == hist->nb_items - 1) {
s->offset = mb->history_saved_offset;
}
@ -6383,12 +6491,11 @@ void do_minibuffer_exit(EditState *s, int do_abort)
/* if completion is activated, then select current file only if
the selection is highlighted */
if (cw && cw->force_highlight) {
int offset, len;
len = eb_fgets(cw->b, buf, sizeof(buf), list_get_offset(cw), &offset);
buf[len] = '\0'; /* strip the trailing newline if any */
int len;
len = mb->completion->get_entry(cw, buf, sizeof(buf), list_get_offset(cw) + 1);
if (len > 0) {
minibuf_set_str(s, buf + 1);
eb_delete_range(s->b, s->b->mark, s->offset); // delete highlighted completion
minibuf_set_str(s, mb->completion_start, mb->completion_end, buf);
}
}
@ -6417,7 +6524,6 @@ void do_minibuffer_exit(EditState *s, int do_abort)
target = s->target_window;
mb->cb = NULL;
mb->opaque = NULL;
qe_free(&mb->completion_name);
/* Close the minibuffer window */
s->b->flags |= BF_TRANSIENT;
@ -6477,11 +6583,13 @@ void minibuffer_edit(EditState *e, const char *input, const char *prompt,
mb = minibuffer_get_state(s, 0);
if (mb) {
mb->completion_popup_window = NULL;
mb->completion_name = NULL;
mb->completion_function = NULL;
mb->completion = NULL;
if (completion_name) {
mb->completion_name = qe_strdup(completion_name);
mb->completion_function = find_completion(completion_name);
if (*completion_name == '.') {
mb->completion_flags = 1;
completion_name++;
}
mb->completion = find_completion(completion_name);
}
mb->history = hist;
mb->history_saved_offset = 0;
@ -8039,13 +8147,13 @@ void do_help_for_help(EditState *s)
if (!b)
return;
eb_printf(b,
"QEmacs help for help - Press q to quit:\n"
"\n"
"C-h C-h Show this help\n"
"C-h b Display table of all key bindings\n"
"C-h c Describe key briefly\n"
);
eb_puts(b,
"QEmacs help for help - Press q to quit:\n"
"\n"
"C-h C-h Show this help\n"
"C-h b Display table of all key bindings\n"
"C-h c Describe key briefly\n"
);
b->flags |= BF_READONLY;
show_popup(s, b, "QEmacs help for help - Press q to quit:");
}
@ -8952,6 +9060,14 @@ typedef struct QEArgs {
char **argv;
} QEArgs;
static CompletionDef charset_completion = {
"charset", charset_complete
};
static CompletionDef color_completion = {
"color", color_complete
};
/* init function */
static void qe_init(void *opaque)
{
@ -8998,14 +9114,14 @@ static void qe_init(void *opaque)
qe_register_cmd_table(basic_commands, NULL);
qe_register_cmd_line_options(cmd_options);
register_completion("command", command_completion);
register_completion("charset", charset_completion);
register_completion("mode", mode_completion);
register_completion("style", style_completion);
register_completion("style-property", style_property_completion);
register_completion("file", file_completion);
register_completion("buffer", buffer_completion);
register_completion("color", color_completion);
qe_register_completion(&command_completion);
qe_register_completion(&charset_completion);
qe_register_completion(&mode_completion);
qe_register_completion(&style_completion);
qe_register_completion(&style_property_completion);
qe_register_completion(&file_completion);
qe_register_completion(&buffer_completion);
qe_register_completion(&color_completion);
minibuffer_init();
popup_init();
@ -9216,7 +9332,7 @@ int main(int argc, char **argv)
}
}
while (qs->first_completion) {
CompletionEntry *cp = qs->first_completion;
CompletionDef *cp = qs->first_completion;
qs->first_completion = cp->next;
qe_free(&cp);
}

39
qe.h
View file

@ -194,7 +194,7 @@ typedef struct CompleteState {
StringArray cs;
struct EditState *s;
struct EditState *target;
int len;
int start, end, len;
char current[MAX_FILENAME_SIZE];
} CompleteState;
@ -502,7 +502,7 @@ unsigned int qe_map_color(QEColor color, QEColor const *colors, int count, int *
/* Convert a composite color to an RGB triplet */
QEColor qe_unmap_color(int color, int count);
void color_completion(CompleteState *cp);
void color_complete(CompleteState *cp);
int css_define_color(const char *name, const char *value);
int css_get_color(QEColor *color_ptr, const char *p);
void css_free_colors(void);
@ -810,7 +810,7 @@ int utf8_decode(const char **pp);
char *utf8_char_to_string(char *buf, int c);
int utf8_to_unicode(unsigned int *dest, int dest_length, const char *str);
void charset_completion(CompleteState *cp);
void charset_complete(CompleteState *cp);
QECharset *find_charset(const char *str);
void charset_decode_init(CharsetDecodeState *s, QECharset *charset,
EOLType eol_type);
@ -1637,7 +1637,7 @@ struct QEmacsState {
struct ModeDef *first_mode;
struct KeyDef *first_key;
struct CmdDef *first_cmd;
struct CompletionEntry *first_completion;
struct CompletionDef *first_completion;
struct HistoryEntry *first_history;
//struct QECharset *first_charset;
//struct QETimer *first_timer;
@ -1819,11 +1819,12 @@ typedef struct CmdDef {
ModeDef *qe_find_mode(const char *name, int flags);
ModeDef *qe_find_mode_filename(const char *filename, int flags);
void qe_register_mode(ModeDef *m, int flags);
void mode_completion(CompleteState *cp);
void mode_complete(CompleteState *cp);
void qe_register_cmd_table(CmdDef *cmds, ModeDef *m);
int qe_register_binding(int key, const char *cmd_name, ModeDef *m);
CmdDef *qe_find_cmd(const char *cmd_name);
int qe_get_prototype(CmdDef *d, char *buf, int size);
int qe_list_bindings(CmdDef *d, ModeDef *mode, int inherit, char *buf, int size);
/* text display system */
@ -1998,25 +1999,29 @@ void minibuffer_init(void);
extern CmdDef minibuffer_commands[];
extern CmdDef popup_commands[];
typedef void (*CompletionFunc)(CompleteState *cp);
typedef struct CompletionEntry {
typedef struct CompletionDef {
const char *name;
CompletionFunc completion_func;
struct CompletionEntry *next;
} CompletionEntry;
void (*enumerate)(CompleteState *cp);
int (*print_entry)(EditState *s, const char *name);
int (*get_entry)(EditState *s, char *dest, int size, int offset);
int flags;
struct CompletionDef *next;
} CompletionDef;
void qe_register_completion(CompletionDef *cp);
void complete_test(CompleteState *cp, const char *str);
void register_completion(const char *name, CompletionFunc completion_func);
void put_status(EditState *s, const char *fmt, ...) qe__attr_printf(2,3);
void put_error(EditState *s, const char *fmt, ...) qe__attr_printf(2,3);
void minibuffer_edit(EditState *e, const char *input, const char *prompt,
StringArray *hist, const char *completion_name,
void (*cb)(void *opaque, char *buf), void *opaque);
void command_completion(CompleteState *cp);
void file_completion(CompleteState *cp);
void buffer_completion(CompleteState *cp);
void command_complete(CompleteState *cp);
int command_print_entry(EditState *s, const char *name);
int command_get_entry(EditState *s, char *dest, int size, int offset);
void file_complete(CompleteState *cp);
void buffer_complete(CompleteState *cp);
#ifdef CONFIG_WIN32
static inline int is_user_input_pending(void) {
@ -2223,9 +2228,9 @@ void do_set_indent_tabs_mode(EditState *s, int val);
void display_window_borders(EditState *e);
int find_style_index(const char *name);
QEStyleDef *find_style(const char *name);
void style_completion(CompleteState *cp);
void style_complete(CompleteState *cp);
void get_style(EditState *e, QEStyleDef *stp, QETermStyle style);
void style_property_completion(CompleteState *cp);
void style_property_complete(CompleteState *cp);
int find_style_property(const char *name);
void do_define_color(EditState *e, const char *name, const char *value);
void do_set_style(EditState *e, const char *stylestr,

View file

@ -112,6 +112,7 @@ static inline void qe_cfg_set_str(QEValue *sp, const char *str, int len) {
sp->u.str = qe_malloc_array(char, len + 1);
memcpy(sp->u.str, str, len);
sp->u.str[len] = '\0';
sp->len = len;
sp->type = TOK_STRING;
}
@ -1163,11 +1164,29 @@ void do_save_session(EditState *s, int popup)
}
#endif
void script_complete(CompleteState *cp) {
command_complete(cp);
variable_complete(cp);
}
int script_print_entry(EditState *s, const char *name) {
CmdDef *d = qe_find_cmd(name);
if (d) {
return command_print_entry(s, name);
} else {
return variable_print_entry(s, name);
}
}
static CompletionDef script_completion = {
"script", script_complete, script_print_entry, command_get_entry
};
static CmdDef parser_commands[] = {
CMD2( KEY_META(':'), KEY_NONE,
"eval-expression", do_eval_expression, ESsi,
"s{Eval: }|expression|ui")
"s{Eval: }[.script]|expression|ui")
CMD0( KEY_NONE, KEY_NONE,
"eval-region", do_eval_region)
CMD0( KEY_NONE, KEY_NONE,
@ -1182,6 +1201,7 @@ static CmdDef parser_commands[] = {
static int parser_init(void)
{
qe_register_cmd_table(parser_commands, NULL);
qe_register_completion(&script_completion);
return 0;
}

4
tty.c
View file

@ -906,7 +906,7 @@ static void comb_cache_describe(QEditScreen *s, EditBuffer *b) {
eb_printf(b, "%*s: fg:%d, bg:%d\n", w, "virtual tty colors",
ts->tty_fg_colors_count, ts->tty_bg_colors_count);
eb_printf(b, "\n");
eb_putc(b, '\n');
eb_printf(b, "Unicode combination cache:\n\n");
for (ip = ts->comb_cache; *ip != 0; ip += *ip & 0xFFFF) {
@ -919,7 +919,7 @@ static void comb_cache_describe(QEditScreen *s, EditBuffer *b) {
for (i = 1; i < (*ip & 0xFFFF); i++) {
eb_printf(b, " %04X", ip[i]);
}
eb_printf(b, "\n");
eb_putc(b, '\n');
}
}
}

2
util.c
View file

@ -1811,7 +1811,7 @@ QEColor qe_unmap_color(int color, int count) {
return color & 0xFFFFFF;
}
void color_completion(CompleteState *cp)
void color_complete(CompleteState *cp)
{
ColorDef const *def;
int count;

View file

@ -115,7 +115,7 @@ VarDef *qe_find_variable(const char *name)
return NULL;
}
void qe_complete_variable(CompleteState *cp)
void variable_complete(CompleteState *cp)
{
QEmacsState *qs = cp->s->qe_state;
const VarDef *vp;
@ -369,6 +369,7 @@ void qe_list_variables(EditState *s, EditBuffer *b)
eb_puts(b, "\n variables:\n\n");
for (vp = qs->first_variable; vp; vp = vp->next) {
/* XXX: merge with variable_print_entry() */
switch (vp->type) {
case VAR_NUMBER:
type = "int";
@ -415,15 +416,67 @@ void qe_save_variables(EditState *s, EditBuffer *b)
eb_putc(b, '\n');
}
int variable_print_entry(EditState *s, const char *name)
{
char buf[256];
char typebuf[32];
const char *type = typebuf;
int len;
VarDef *vp = qe_find_variable(name);
EditBuffer *b = s->b;
len = eb_puts(b, name);
if (!vp)
return len;
switch (vp->type) {
case VAR_NUMBER:
type = "int";
break;
case VAR_STRING:
type = "string";
break;
case VAR_CHARS:
snprintf(typebuf, sizeof(typebuf), "char[%d]", vp->size);
break;
default:
type = "var";
break;
}
len += eb_printf(b, " = ");
qe_get_variable(s, vp->name, buf, sizeof(buf), NULL, 1);
if (*buf == '\"')
b->cur_style = QE_STYLE_STRING;
else
b->cur_style = QE_STYLE_NUMBER;
len += eb_puts(b, buf);
b->cur_style = QE_STYLE_COMMENT;
if (2 + len < 40) {
b->tab_width = max(2 + len, b->tab_width);
len += eb_putc(b, '\t');
} else {
b->tab_width = 40;
}
len += eb_printf(b, " %s%s %s",
vp->rw ? "" : "read-only ",
var_domain[vp->domain], type);
b->cur_style = QE_STYLE_DEFAULT;
return len;
}
static CompletionDef variable_completion = {
"variable", variable_complete, variable_print_entry, command_get_entry
};
/*---------------- commands ----------------*/
static CmdDef var_commands[] = {
CMD2( KEY_NONE, KEY_NONE,
"show-variable", do_show_variable, ESs,
"s{Show variable: }[var]|var|")
"s{Show variable: }[variable]|variable|")
CMD2( KEY_F8, KEY_NONE,
"set-variable", do_set_variable, ESss,
"s{Set variable: }[var]|var|s{to value: }|value|")
"s{Set variable: }[variable]|variable|s{to value: }|value|")
CMD_DEF_END,
};
@ -432,7 +485,7 @@ static int vars_init(void)
{
qe_register_variables(var_table, countof(var_table));
qe_register_cmd_table(var_commands, NULL);
register_completion("var", qe_complete_variable);
qe_register_completion(&variable_completion);
return 0;
}

View file

@ -95,7 +95,8 @@ struct VarDef {
void qe_register_variables(VarDef *vars, int count);
VarDef *qe_find_variable(const char *name);
void qe_complete_variable(CompleteState *cp);
void variable_complete(CompleteState *cp);
int variable_print_entry(EditState *s, const char *name);
QVarType qe_get_variable(EditState *s, const char *name,
char *buf, int size, int *pnum, int as_source);