Improve command argument parsing
- add CmdArgSpec structure for parse_arg() - add argument type prefixes for defautl values: 'm' prefix for CMD_ARG_USE_MARK, 'p' for CMD_ARG_USE_POINT 'z' for CMD_ARG_USE_ZERO and 'e' for CMD_ARG_USE_BSIZE, - rename parse_args as parse_arguments to avoid confusion with parse_arg - make tabify-region and tabify-buffer call do_tabify() - make untabify-region and untabify-buffer call do_untabify() - move command argument specification to CmdDef:spec, followed by description string
This commit is contained in:
parent
6a50b76644
commit
e1cd76cc3c
6 changed files with 223 additions and 164 deletions
2
clang.c
2
clang.c
|
|
@ -1316,7 +1316,7 @@ static CmdDef c_commands[] = {
|
|||
CMD2( '{', '}',
|
||||
"c-electric-key", do_c_electric, ESi, "*ki")
|
||||
CMD2( KEY_RET, KEY_NONE,
|
||||
"c-newline", do_c_newline, ES, "*v")
|
||||
"c-newline", do_c_newline, ES, "*")
|
||||
CMD_DEF_END,
|
||||
};
|
||||
|
||||
|
|
|
|||
46
extras.c
46
extras.c
|
|
@ -324,7 +324,7 @@ static void do_delete_blank_lines(EditState *s)
|
|||
eb_delete_range(b, from, offset);
|
||||
}
|
||||
|
||||
static void eb_tabify(EditBuffer *b, int p1, int p2)
|
||||
static void do_tabify(EditState *s, int p1, int p2)
|
||||
{
|
||||
/* We implement a complete analysis of the region instead of
|
||||
* scanning for certain space patterns (such as / [ \t]/). It is
|
||||
|
|
@ -338,12 +338,16 @@ static void eb_tabify(EditBuffer *b, int p1, int p2)
|
|||
* new buffer reader eb_nextc_style() using colorizer and a
|
||||
* one line cache.
|
||||
*/
|
||||
EditBuffer *b = s->b;
|
||||
int tw = b->tab_width > 0 ? b->tab_width : 8;
|
||||
int start = max(0, min(p1, p2));
|
||||
int stop = min(b->total_size, max(p1, p2));
|
||||
int col;
|
||||
int offset, offset1, offset2, delta;
|
||||
|
||||
/* deactivate region hilite */
|
||||
s->region_style = 0;
|
||||
|
||||
col = 0;
|
||||
offset = eb_goto_bol(b, start);
|
||||
|
||||
|
|
@ -385,7 +389,7 @@ static void eb_tabify(EditBuffer *b, int p1, int p2)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void do_tabify_buffer(EditState *s)
|
||||
{
|
||||
/* deactivate region hilite */
|
||||
|
|
@ -401,19 +405,23 @@ static void do_tabify_region(EditState *s)
|
|||
|
||||
eb_tabify(s->b, s->b->mark, s->offset);
|
||||
}
|
||||
|
||||
static void eb_untabify(EditBuffer *b, int p1, int p2)
|
||||
#endif
|
||||
static void do_untabify(EditState *s, int p1, int p2)
|
||||
{
|
||||
/* We implement a complete analysis of the region instead of
|
||||
* potentially faster scan for '\t'. It is fast enough and even
|
||||
* faster if there are lots of tabs.
|
||||
*/
|
||||
EditBuffer *b = s->b;
|
||||
int tw = b->tab_width > 0 ? b->tab_width : 8;
|
||||
int start = max(0, min(p1, p2));
|
||||
int stop = min(b->total_size, max(p1, p2));
|
||||
int col, col0;
|
||||
int offset, offset1, offset2, delta;
|
||||
|
||||
/* deactivate region hilite */
|
||||
s->region_style = 0;
|
||||
|
||||
col = 0;
|
||||
offset = eb_goto_bol(b, start);
|
||||
|
||||
|
|
@ -441,7 +449,7 @@ static void eb_untabify(EditBuffer *b, int p1, int p2)
|
|||
stop += delta;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void do_untabify_buffer(EditState *s)
|
||||
{
|
||||
/* deactivate region hilite */
|
||||
|
|
@ -457,7 +465,7 @@ static void do_untabify_region(EditState *s)
|
|||
|
||||
eb_untabify(s->b, s->b->mark, s->offset);
|
||||
}
|
||||
|
||||
#endif
|
||||
static void do_indent_region(EditState *s)
|
||||
{
|
||||
int col_num, line1, line2;
|
||||
|
|
@ -988,15 +996,16 @@ void do_apropos(EditState *s, const char *str)
|
|||
while (d != NULL) {
|
||||
while (d->name != NULL) {
|
||||
if (strstr(d->name, str)) {
|
||||
const char *desc;
|
||||
/* print name and prototype */
|
||||
qe_get_prototype(d, buf, sizeof(buf));
|
||||
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_putc(b, '\n');
|
||||
if (d->desc && *d->desc) {
|
||||
if (*(desc = d->spec + strlen(d->spec) + 1)) {
|
||||
/* print short description */
|
||||
eb_printf(b, " %s", d->desc);
|
||||
eb_printf(b, " %s", desc);
|
||||
}
|
||||
eb_putc(b, '\n');
|
||||
found = 1;
|
||||
|
|
@ -1878,15 +1887,18 @@ static CmdDef extra_commands[] = {
|
|||
"delete-horizontal-space", do_delete_horizontal_space, ES, "*")
|
||||
CMD2( KEY_CTRLX(KEY_CTRL('o')), KEY_NONE,
|
||||
"delete-blank-lines", do_delete_blank_lines, ES, "*")
|
||||
/* XXX: should take region as argument, implicit from keyboard */
|
||||
CMD2( KEY_NONE, KEY_NONE,
|
||||
"tabify-region", do_tabify_region, ES, "*")
|
||||
CMD2( KEY_NONE, KEY_NONE,
|
||||
"untabify-region", do_untabify_region, ES, "*")
|
||||
CMD2( KEY_NONE, KEY_NONE,
|
||||
"tabify-buffer", do_tabify_buffer, ES, "*")
|
||||
CMD2( KEY_NONE, KEY_NONE,
|
||||
"untabify-buffer", do_untabify_buffer, ES, "*")
|
||||
CMD3( KEY_NONE, KEY_NONE,
|
||||
"tabify-region", do_tabify, ESii, 0, "*" "mipi"
|
||||
"\0" "Convert multiple spaces in region to tabs when possible")
|
||||
CMD3( KEY_NONE, KEY_NONE,
|
||||
"untabify-region", do_untabify, ESii, 0, "*" "mipi"
|
||||
"\0" "Convert all tabs in region to multiple spaces, preserving columns")
|
||||
CMD3( KEY_NONE, KEY_NONE,
|
||||
"tabify-buffer", do_tabify, ESii, 0, "*" "ziei"
|
||||
"\0" "Convert multiple spaces in buffer to tabs when possible")
|
||||
CMD3( KEY_NONE, KEY_NONE,
|
||||
"untabify-buffer", do_untabify, ESii, 0, "*" "ziei"
|
||||
"\0" "Convert all tabs in buffer to multiple spaces, preserving columns")
|
||||
/* XXX: should take region as argument, implicit from keyboard */
|
||||
CMD2( KEY_META(KEY_CTRL('\\')), KEY_NONE,
|
||||
"indent-region", do_indent_region, ES, "*")
|
||||
|
|
|
|||
30
parser.c
30
parser.c
|
|
@ -124,11 +124,12 @@ static int qe_parse_script(EditState *s, QEmacsDataSource *ds)
|
|||
QEmacsState *qs = s->qe_state;
|
||||
QErrorContext ec;
|
||||
char line[1024], str[1024];
|
||||
char prompt[64], cmd[128], *q, *strp;
|
||||
char cmd[128], *q, *strp;
|
||||
CmdArgSpec cas;
|
||||
const char *p, *r;
|
||||
int line_num;
|
||||
CmdDef *d;
|
||||
int nb_args, sep, i, skip, incomment;
|
||||
int nb_args, sep, i, skip, incomment, ret;
|
||||
CmdArg args[MAX_CMD_ARGS];
|
||||
unsigned char args_type[MAX_CMD_ARGS];
|
||||
|
||||
|
|
@ -240,7 +241,7 @@ static int qe_parse_script(EditState *s, QEmacsDataSource *ds)
|
|||
nb_args = 0;
|
||||
|
||||
/* construct argument type list */
|
||||
r = d->name + strlen(d->name) + 1;
|
||||
r = d->spec;
|
||||
if (*r == '*') {
|
||||
r++;
|
||||
if (s->b->flags & BF_READONLY) {
|
||||
|
|
@ -252,23 +253,13 @@ static int qe_parse_script(EditState *s, QEmacsDataSource *ds)
|
|||
/* first argument is always the window */
|
||||
args_type[nb_args++] = CMD_ARG_WINDOW;
|
||||
|
||||
for (;;) {
|
||||
unsigned char arg_type;
|
||||
int ret;
|
||||
|
||||
ret = parse_arg(&r, &arg_type, prompt, countof(prompt),
|
||||
NULL, 0, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto badcmd;
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (nb_args >= MAX_CMD_ARGS) {
|
||||
badcmd:
|
||||
while ((ret = parse_arg(&r, &cas)) != 0) {
|
||||
if (ret < 0 || nb_args >= MAX_CMD_ARGS) {
|
||||
put_status(s, "Badly defined command '%s'", cmd);
|
||||
goto fail;
|
||||
}
|
||||
args[nb_args].p = NULL;
|
||||
args_type[nb_args++] = arg_type & CMD_ARG_TYPE_MASK;
|
||||
args_type[nb_args++] = cas.arg_type & CMD_ARG_TYPE_MASK;
|
||||
}
|
||||
|
||||
sep = '\0';
|
||||
|
|
@ -284,8 +275,9 @@ static int qe_parse_script(EditState *s, QEmacsDataSource *ds)
|
|||
args[i].n = (int)(intptr_t)d->val;
|
||||
continue;
|
||||
case CMD_ARG_STRINGVAL:
|
||||
/* CG: kludge for xxx-mode functions and named kbd macros */
|
||||
args[i].p = prompt;
|
||||
/* CG: kludge for xxx-mode functions and named kbd macros,
|
||||
must be last argument */
|
||||
args[i].p = cas.prompt;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +290,7 @@ static int qe_parse_script(EditState *s, QEmacsDataSource *ds)
|
|||
sep = ',';
|
||||
skip_spaces(&p);
|
||||
|
||||
switch (args_type[i]) {
|
||||
switch (args_type[i] & CMD_ARG_TYPE_MASK) {
|
||||
case CMD_ARG_INT:
|
||||
r = p;
|
||||
args[i].n = strtol(p, (char**)&p, 0);
|
||||
|
|
|
|||
208
qe.c
208
qe.c
|
|
@ -183,20 +183,23 @@ void qe_register_mode(ModeDef *m, int flags)
|
|||
|
||||
/* add a new command to switch to that mode */
|
||||
if (!(m->flags & MODEF_NOCMD)) {
|
||||
char buf[64];
|
||||
int size;
|
||||
char name[64];
|
||||
char spec[64];
|
||||
int spec_len;
|
||||
CmdDef *def;
|
||||
const char *mode_name = m->alt_name ? m->alt_name : m->name;
|
||||
|
||||
/* lower case convert for C mode, Perl... */
|
||||
qe_strtolower(buf, sizeof(buf) - 10, mode_name);
|
||||
pstrcat(buf, sizeof(buf), "-mode");
|
||||
size = strlen(buf) + 1;
|
||||
qe_strtolower(name, sizeof(name) - 10, mode_name);
|
||||
pstrcat(name, sizeof(name), "-mode");
|
||||
|
||||
/* constant immediate string parameter */
|
||||
size += snprintf(buf + size, sizeof(buf) - size,
|
||||
"S{%s}", mode_name) + 1;
|
||||
spec_len = snprintf(spec, sizeof(spec),
|
||||
"S{%s}%cselect the %s mode for the current buffer",
|
||||
mode_name, 0, mode_name);
|
||||
def = qe_mallocz_array(CmdDef, 2);
|
||||
def->name = qe_malloc_dup(buf, size);
|
||||
def->name = qe_strdup(name);
|
||||
def->spec = qe_malloc_dup(spec, spec_len + 1);
|
||||
def->key = def->alt_key = KEY_NONE;
|
||||
def->sig = CMD_ESs;
|
||||
def->val = 0;
|
||||
|
|
@ -4761,30 +4764,45 @@ static void get_param(const char **pp, char *param, int param_size, int osep, in
|
|||
}
|
||||
|
||||
/* return -1 if error, 0 if no more args, 1 if one arg parsed */
|
||||
int parse_arg(const char **pp, unsigned char *argtype,
|
||||
char *prompt, int prompt_size,
|
||||
char *completion, int completion_size,
|
||||
char *history, int history_size)
|
||||
int parse_arg(const char **pp, CmdArgSpec *ap)
|
||||
{
|
||||
int tc, type;
|
||||
const char *p;
|
||||
|
||||
p = *pp;
|
||||
type = 0;
|
||||
if (*p == 'k') {
|
||||
p++;
|
||||
switch (*p) {
|
||||
case 'k':
|
||||
type = CMD_ARG_USE_KEY;
|
||||
}
|
||||
if (*p == 'u') {
|
||||
p++;
|
||||
break;
|
||||
case 'u':
|
||||
type = CMD_ARG_USE_ARGVAL;
|
||||
p++;
|
||||
break;
|
||||
case 'm':
|
||||
type = CMD_ARG_USE_MARK;
|
||||
p++;
|
||||
break;
|
||||
case 'p':
|
||||
type = CMD_ARG_USE_POINT;
|
||||
p++;
|
||||
break;
|
||||
case 'z':
|
||||
type = CMD_ARG_USE_ZERO;
|
||||
p++;
|
||||
break;
|
||||
case 'e':
|
||||
type = CMD_ARG_USE_BSIZE;
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
if (*p == '\0')
|
||||
return 0;
|
||||
tc = *p++;
|
||||
get_param(&p, prompt, prompt_size, '{', '}');
|
||||
get_param(&p, completion, completion_size, '[', ']');
|
||||
get_param(&p, history, history_size, '|', '|');
|
||||
get_param(&p, ap->prompt, sizeof(ap->prompt), '{', '}');
|
||||
get_param(&p, ap->completion, sizeof(ap->completion), '[', ']');
|
||||
get_param(&p, ap->history, sizeof(ap->history), '|', '|');
|
||||
switch (tc) {
|
||||
case 'i':
|
||||
type |= CMD_ARG_INT;
|
||||
|
|
@ -4796,13 +4814,14 @@ int parse_arg(const char **pp, unsigned char *argtype,
|
|||
type |= CMD_ARG_STRING;
|
||||
break;
|
||||
case 'S': /* used in define_kbd_macro, and mode selection */
|
||||
/* actual string is in prompt buffer */
|
||||
type |= CMD_ARG_STRINGVAL;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
*pp = p;
|
||||
*argtype = type;
|
||||
ap->arg_type = type;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -4811,31 +4830,20 @@ int qe_get_prototype(CmdDef *d, char *buf, int size)
|
|||
buf_t outbuf, *out;
|
||||
const char *r;
|
||||
const char *sep = "";
|
||||
CmdArgSpec cas;
|
||||
|
||||
out = buf_init(&outbuf, buf, size);
|
||||
|
||||
buf_put_byte(out, '(');
|
||||
|
||||
/* construct argument type list */
|
||||
r = d->name + strlen(d->name) + 1;
|
||||
r = d->spec;
|
||||
if (*r == '*') {
|
||||
r++; /* buffer modification indicator */
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
unsigned char arg_type;
|
||||
char completion[32];
|
||||
char history[32];
|
||||
int ret;
|
||||
|
||||
ret = parse_arg(&r, &arg_type, NULL, 0,
|
||||
completion, sizeof(completion),
|
||||
history, sizeof(history));
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
/* pseudo arguments: skip them */
|
||||
switch (arg_type & CMD_ARG_TYPE_MASK) {
|
||||
while (parse_arg(&r, &cas) > 0) {
|
||||
switch (cas.arg_type & CMD_ARG_TYPE_MASK) {
|
||||
case CMD_ARG_INT:
|
||||
buf_printf(out, "%sint ", sep);
|
||||
break;
|
||||
|
|
@ -4849,13 +4857,28 @@ int qe_get_prototype(CmdDef *d, char *buf, int size)
|
|||
continue;
|
||||
}
|
||||
sep = ", ";
|
||||
if (arg_type & CMD_ARG_USE_KEY) {
|
||||
buf_puts(out, "key");
|
||||
} else
|
||||
if (arg_type & CMD_ARG_USE_ARGVAL) {
|
||||
buf_puts(out, "argval");
|
||||
} else {
|
||||
buf_puts(out, *history ? history : completion);
|
||||
switch (cas.arg_type & ~CMD_ARG_TYPE_MASK) {
|
||||
case CMD_ARG_USE_ARGVAL:
|
||||
buf_puts(out, "= argval");
|
||||
break;
|
||||
case CMD_ARG_USE_KEY:
|
||||
buf_puts(out, "= key");
|
||||
break;
|
||||
case CMD_ARG_USE_MARK:
|
||||
buf_puts(out, "= mark");
|
||||
break;
|
||||
case CMD_ARG_USE_POINT:
|
||||
buf_puts(out, "= point");
|
||||
break;
|
||||
case CMD_ARG_USE_ZERO:
|
||||
buf_puts(out, "= 0");
|
||||
break;
|
||||
case CMD_ARG_USE_BSIZE:
|
||||
buf_puts(out, "= bufsize");
|
||||
break;
|
||||
default:
|
||||
buf_puts(out, *cas.history ? cas.history : cas.completion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf_put_byte(out, ')');
|
||||
|
|
@ -4863,7 +4886,7 @@ int qe_get_prototype(CmdDef *d, char *buf, int size)
|
|||
}
|
||||
|
||||
static void arg_edit_cb(void *opaque, char *str);
|
||||
static void parse_args(ExecCmdState *es);
|
||||
static void parse_arguments(ExecCmdState *es);
|
||||
static void free_cmd(ExecCmdState **esp);
|
||||
|
||||
void exec_command(EditState *s, CmdDef *d, int argval, int key)
|
||||
|
|
@ -4874,7 +4897,7 @@ void exec_command(EditState *s, CmdDef *d, int argval, int key)
|
|||
if (qe_state.trace_buffer && qe_state.trace_buffer != s->b)
|
||||
eb_trace_bytes(d->name, -1, EB_TRACE_COMMAND);
|
||||
|
||||
argdesc = d->name + strlen(d->name) + 1;
|
||||
argdesc = d->spec;
|
||||
if (*argdesc == '*') {
|
||||
argdesc++;
|
||||
if (s->b->flags & BF_READONLY) {
|
||||
|
|
@ -4899,37 +4922,25 @@ void exec_command(EditState *s, CmdDef *d, int argval, int key)
|
|||
es->nb_args++;
|
||||
es->ptype = argdesc;
|
||||
|
||||
parse_args(es);
|
||||
parse_arguments(es);
|
||||
}
|
||||
|
||||
/* parse as much arguments as possible. ask value to user if possible */
|
||||
static void parse_args(ExecCmdState *es)
|
||||
static void parse_arguments(ExecCmdState *es)
|
||||
{
|
||||
EditState *s = es->s;
|
||||
QEmacsState *qs = s->qe_state;
|
||||
QErrorContext ec;
|
||||
CmdDef *d = es->d;
|
||||
char prompt[256];
|
||||
char completion_name[64];
|
||||
char history[32];
|
||||
unsigned char arg_type;
|
||||
int ret, rep_count, get_arg, type, use_argval, use_key;
|
||||
CmdArgSpec cas;
|
||||
int ret, rep_count, get_arg, type, use_flag;
|
||||
int elapsed_time;
|
||||
|
||||
for (;;) {
|
||||
ret = parse_arg(&es->ptype, &arg_type,
|
||||
prompt, sizeof(prompt),
|
||||
completion_name, sizeof(completion_name),
|
||||
history, sizeof(history));
|
||||
if (ret < 0)
|
||||
while ((ret = parse_arg(&es->ptype, &cas)) != 0) {
|
||||
if (ret < 0 || es->nb_args >= MAX_CMD_ARGS)
|
||||
goto fail;
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (es->nb_args >= MAX_CMD_ARGS)
|
||||
goto fail;
|
||||
use_argval = arg_type & CMD_ARG_USE_ARGVAL;
|
||||
use_key = arg_type & CMD_ARG_USE_KEY;
|
||||
type = arg_type & CMD_ARG_TYPE_MASK;
|
||||
use_flag = cas.arg_type & ~CMD_ARG_TYPE_MASK;
|
||||
type = cas.arg_type & CMD_ARG_TYPE_MASK;
|
||||
es->args_type[es->nb_args] = type;
|
||||
get_arg = 0;
|
||||
switch (type) {
|
||||
|
|
@ -4937,13 +4948,27 @@ static void parse_args(ExecCmdState *es)
|
|||
es->args[es->nb_args].n = d->val;
|
||||
break;
|
||||
case CMD_ARG_STRINGVAL:
|
||||
es->args[es->nb_args].p = prompt;
|
||||
/* CG: kludge for xxx-mode functions and named kbd macros,
|
||||
must be last argument */
|
||||
es->args[es->nb_args].p = cas.prompt;
|
||||
break;
|
||||
case CMD_ARG_INT:
|
||||
if (use_key) {
|
||||
if (use_flag == CMD_ARG_USE_KEY) {
|
||||
es->args[es->nb_args].n = es->key;
|
||||
} else
|
||||
if (use_argval && es->argval != NO_ARG) {
|
||||
if (use_flag == CMD_ARG_USE_MARK) {
|
||||
es->args[es->nb_args].n = s->b->mark;
|
||||
} else
|
||||
if (use_flag == CMD_ARG_USE_POINT) {
|
||||
es->args[es->nb_args].n = s->offset;
|
||||
} else
|
||||
if (use_flag == CMD_ARG_USE_ZERO) {
|
||||
es->args[es->nb_args].n = 0;
|
||||
} else
|
||||
if (use_flag == CMD_ARG_USE_BSIZE) {
|
||||
es->args[es->nb_args].n = s->b->total_size;
|
||||
} else
|
||||
if (use_flag == CMD_ARG_USE_ARGVAL && es->argval != NO_ARG) {
|
||||
es->args[es->nb_args].n = es->argval;
|
||||
es->argval = NO_ARG;
|
||||
} else {
|
||||
|
|
@ -4953,12 +4978,15 @@ static void parse_args(ExecCmdState *es)
|
|||
}
|
||||
break;
|
||||
case CMD_ARG_STRING:
|
||||
if (use_argval && es->argval != NO_ARG) {
|
||||
#if 0
|
||||
if (use_flag == CMD_ARG_USE_ARGVAL && es->argval != NO_ARG) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%d", es->argval);
|
||||
es->args[es->nb_args].p = qe_strdup(buf);
|
||||
es->args[es->nb_args].p = qe_strdup(buf); // XXX: memory leak?
|
||||
es->argval = NO_ARG;
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
es->args[es->nb_args].p = NULL;
|
||||
get_arg = 1;
|
||||
break;
|
||||
|
|
@ -4966,17 +4994,17 @@ static void parse_args(ExecCmdState *es)
|
|||
}
|
||||
es->nb_args++;
|
||||
/* if no argument specified, try to ask it to the user */
|
||||
if (get_arg && prompt[0] != '\0') {
|
||||
if (get_arg && cas.prompt[0] != '\0') {
|
||||
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")) {
|
||||
if (strequal(cas.completion, "file")) {
|
||||
get_default_path(s->b, s->offset, def_input, sizeof(def_input));
|
||||
} else
|
||||
if (strequal(completion_name, "buffer")) {
|
||||
if (strequal(cas.completion, "buffer")) {
|
||||
EditBuffer *b;
|
||||
if (d->action.ESs == do_switch_to_buffer)
|
||||
b = predict_switch_to_buffer(s);
|
||||
|
|
@ -4985,12 +5013,12 @@ static void parse_args(ExecCmdState *es)
|
|||
pstrcpy(es->default_input, sizeof(es->default_input), b->name);
|
||||
}
|
||||
if (es->default_input[0] != '\0') {
|
||||
pstrcat(prompt, sizeof(prompt), "(default ");
|
||||
pstrcat(prompt, sizeof(prompt), es->default_input);
|
||||
pstrcat(prompt, sizeof(prompt), ") ");
|
||||
pstrcat(cas.prompt, sizeof(cas.prompt), "(default ");
|
||||
pstrcat(cas.prompt, sizeof(cas.prompt), es->default_input);
|
||||
pstrcat(cas.prompt, sizeof(cas.prompt), ") ");
|
||||
}
|
||||
minibuffer_edit(s, def_input, prompt, get_history(history),
|
||||
completion_name, arg_edit_cb, es);
|
||||
minibuffer_edit(s, def_input, cas.prompt, get_history(cas.history),
|
||||
cas.completion, arg_edit_cb, es);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -5007,6 +5035,7 @@ static void parse_args(ExecCmdState *es)
|
|||
|
||||
qs->cmd_start_time = get_clock_ms();
|
||||
|
||||
// XXX: should use while (rep_count-- > 0)
|
||||
do {
|
||||
/* special case for hex mode */
|
||||
if (d->action.ESii != do_char) {
|
||||
|
|
@ -5090,7 +5119,7 @@ static void arg_edit_cb(void *opaque, char *str)
|
|||
break;
|
||||
}
|
||||
/* now we can parse the following arguments */
|
||||
parse_args(es);
|
||||
parse_arguments(es);
|
||||
}
|
||||
|
||||
int check_read_only(EditState *s)
|
||||
|
|
@ -5297,11 +5326,10 @@ void do_define_kbd_macro(EditState *s, const char *name, const char *keys,
|
|||
const char *key_bind)
|
||||
{
|
||||
CmdDef *def;
|
||||
int namelen, size;
|
||||
int size;
|
||||
char *buf;
|
||||
|
||||
namelen = strlen(name);
|
||||
size = namelen + 1 + 2 + strlen(keys) + 2;
|
||||
size = 2 + strlen(keys) + 3;
|
||||
buf = qe_malloc_array(char, size);
|
||||
|
||||
// XXX: should special case "last-kbd-macro"
|
||||
|
|
@ -5309,7 +5337,7 @@ void do_define_kbd_macro(EditState *s, const char *name, const char *keys,
|
|||
/* CG: should parse macro keys to an array and pass index
|
||||
* to do_execute_macro.
|
||||
*/
|
||||
snprintf(buf, size, "%s%cS{%s}", name, 0, keys);
|
||||
snprintf(buf, size, "S{%s}%c", keys, 0);
|
||||
|
||||
def = qe_find_cmd(name);
|
||||
if (def && def->action.ESs == do_execute_macro_keys) {
|
||||
|
|
@ -5317,12 +5345,13 @@ void do_define_kbd_macro(EditState *s, const char *name, const char *keys,
|
|||
/* XXX: freeing the current macro definition may cause a crash if it
|
||||
* is currently executing.
|
||||
*/
|
||||
qe_free((char **)&def->name);
|
||||
def->name = buf;
|
||||
qe_free((char **)&def->spec);
|
||||
def->spec = buf;
|
||||
} else {
|
||||
def = qe_mallocz_array(CmdDef, 2);
|
||||
def->key = def->alt_key = KEY_NONE;
|
||||
def->name = buf;
|
||||
def->name = qe_strdup(name);
|
||||
def->spec = buf;
|
||||
def->sig = CMD_ESs;
|
||||
def->val = 0;
|
||||
def->action.ESs = do_execute_macro_keys;
|
||||
|
|
@ -5348,9 +5377,8 @@ static void qe_save_macro(EditState *s, CmdDef *def, EditBuffer *b)
|
|||
eb_printf(b, "define_kbd_macro(\"%s\", \"", name);
|
||||
|
||||
if (def) {
|
||||
const char *keys = def->name;
|
||||
keys += strlen(keys) + 1 + 2;
|
||||
while (keys[1]) {
|
||||
const char *keys = def->spec + 2; /* skip S{ */
|
||||
while (keys[1]) { /* stop at } */
|
||||
eb_putc(b, utf8_decode(&keys));
|
||||
}
|
||||
} else {
|
||||
|
|
@ -9397,8 +9425,10 @@ int main(int argc, char **argv)
|
|||
d1++;
|
||||
qs->first_cmd = d1->action.next;
|
||||
/* free xxx-mode commands and macros */
|
||||
/* XXX: should use CmdDef flag */
|
||||
if (d->name && !d[1].name && d[1].val) {
|
||||
qe_free((char **)&d->name);
|
||||
qe_free((char **)&d->spec);
|
||||
qe_free(&d);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
44
qe.h
44
qe.h
|
|
@ -1758,9 +1758,13 @@ enum CmdArgType {
|
|||
CMD_ARG_STRING,
|
||||
CMD_ARG_STRINGVAL,
|
||||
CMD_ARG_WINDOW,
|
||||
CMD_ARG_TYPE_MASK = 0x3f,
|
||||
CMD_ARG_USE_KEY = 0x40,
|
||||
CMD_ARG_USE_ARGVAL = 0x80,
|
||||
CMD_ARG_TYPE_MASK = 0x0f,
|
||||
CMD_ARG_USE_ARGVAL = 0x10,
|
||||
CMD_ARG_USE_KEY = 0x20,
|
||||
CMD_ARG_USE_MARK = 0x30,
|
||||
CMD_ARG_USE_POINT = 0x40,
|
||||
CMD_ARG_USE_ZERO = 0x50,
|
||||
CMD_ARG_USE_BSIZE = 0x60,
|
||||
};
|
||||
|
||||
typedef enum CmdSig {
|
||||
|
|
@ -1783,6 +1787,13 @@ typedef union CmdArg {
|
|||
int n;
|
||||
} CmdArg;
|
||||
|
||||
typedef struct CmdArgSpec {
|
||||
int arg_type;
|
||||
char completion[32];
|
||||
char history[32];
|
||||
char prompt[1024]; /* used for keyboard macros */
|
||||
} CmdArgSpec;
|
||||
|
||||
typedef union CmdProto {
|
||||
void (*func)(void);
|
||||
void (*ES)(EditState *);
|
||||
|
|
@ -1798,7 +1809,7 @@ typedef union CmdProto {
|
|||
|
||||
typedef struct CmdDef {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
const char *spec;
|
||||
unsigned short key; /* normal key */
|
||||
unsigned short alt_key; /* alternate key */
|
||||
CmdSig sig : 8;
|
||||
|
|
@ -1806,17 +1817,19 @@ typedef struct CmdDef {
|
|||
CmdProto action;
|
||||
} CmdDef;
|
||||
|
||||
/* new command macros */
|
||||
#define CMD2(key, key_alt, name, func, sig, args) \
|
||||
{ name "\0" args, NULL, key, key_alt, CMD_ ## sig, 0, { .sig = func } },
|
||||
#define CMD3(key, key_alt, name, func, sig, val, args) \
|
||||
{ name "\0" args, NULL, key, key_alt, CMD_ ## sig, val, { .sig = func } },
|
||||
|
||||
/* old macros for compatibility */
|
||||
/* command without arguments, no buffer modification */
|
||||
#define CMD0(key, key_alt, name, func) \
|
||||
{ name "\0", NULL, key, key_alt, CMD_ES, 0, { .ES = func } },
|
||||
{ name, "" "\0" "", key, key_alt, CMD_ES, 0, { .ES = func } },
|
||||
/* command with a single implicit int argument */
|
||||
#define CMD1(key, key_alt, name, func, val) \
|
||||
{ name "\0" "v", NULL, key, key_alt, CMD_ESi, val, { .ESi = func } },
|
||||
{ name, "v" "\0" "", key, key_alt, CMD_ESi, val, { .ESi = func } },
|
||||
/* command with a an argument description string */
|
||||
#define CMD2(key, key_alt, name, func, sig, spec) \
|
||||
{ name, spec "\0" "", key, key_alt, CMD_ ## sig, 0, { .sig = func } },
|
||||
/* command with a an argument description string and an int agument */
|
||||
#define CMD3(key, key_alt, name, func, sig, val, spec) \
|
||||
{ name, spec "\0" "", key, key_alt, CMD_ ## sig, val, { .sig = func } },
|
||||
/* end of command definitions */
|
||||
#define CMD_DEF_END \
|
||||
{ NULL, NULL, 0, 0, CMD_void, 0, { NULL } }
|
||||
|
||||
|
|
@ -2252,10 +2265,7 @@ void do_set_system_font(EditState *s, const char *qe_font_name,
|
|||
void do_set_window_style(EditState *s, const char *stylestr);
|
||||
void call_func(CmdSig sig, CmdProto func, int nb_args, CmdArg *args,
|
||||
unsigned char *args_type);
|
||||
int parse_arg(const char **pp, unsigned char *argtype,
|
||||
char *prompt, int prompt_size,
|
||||
char *completion, int completion_size,
|
||||
char *history, int history_size);
|
||||
int parse_arg(const char **pp, CmdArgSpec *ap);
|
||||
void exec_command(EditState *s, CmdDef *d, int argval, int key);
|
||||
void do_execute_command(EditState *s, const char *cmd, int argval);
|
||||
void window_display(EditState *s);
|
||||
|
|
|
|||
57
qescript.c
57
qescript.c
|
|
@ -817,19 +817,20 @@ done:
|
|||
}
|
||||
|
||||
static int qe_cfg_call(QEmacsDataSource *ds, QEValue *sp, CmdDef *d) {
|
||||
char str[1024], prompt[64];
|
||||
char str[1024];
|
||||
char *strp;
|
||||
const char *r;
|
||||
int nb_args, sep, i;
|
||||
int nb_args, sep, i, ret;
|
||||
CmdArg args[MAX_CMD_ARGS];
|
||||
unsigned char args_type[MAX_CMD_ARGS];
|
||||
EditState *s = ds->s;
|
||||
QEmacsState *qs = s->qe_state;
|
||||
CmdArgSpec cas;
|
||||
|
||||
nb_args = 0;
|
||||
|
||||
/* construct argument type list */
|
||||
r = d->name + strlen(d->name) + 1;
|
||||
r = d->spec;
|
||||
if (*r == '*') {
|
||||
r++;
|
||||
if (s->b->flags & BF_READONLY) {
|
||||
|
|
@ -841,23 +842,13 @@ static int qe_cfg_call(QEmacsDataSource *ds, QEValue *sp, CmdDef *d) {
|
|||
/* first argument is always the window */
|
||||
args_type[nb_args++] = CMD_ARG_WINDOW;
|
||||
|
||||
for (;;) {
|
||||
unsigned char arg_type;
|
||||
int ret;
|
||||
|
||||
ret = parse_arg(&r, &arg_type, prompt, countof(prompt),
|
||||
NULL, 0, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto badcmd;
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (nb_args >= MAX_CMD_ARGS) {
|
||||
badcmd:
|
||||
while ((ret = parse_arg(&r, &cas)) != 0) {
|
||||
if (ret < 0 || nb_args >= MAX_CMD_ARGS) {
|
||||
put_status(s, "Badly defined command '%s'", d->name);
|
||||
return -1;
|
||||
}
|
||||
args[nb_args].p = NULL;
|
||||
args_type[nb_args++] = arg_type & (CMD_ARG_TYPE_MASK | CMD_ARG_USE_ARGVAL);
|
||||
args_type[nb_args++] = cas.arg_type;
|
||||
}
|
||||
|
||||
sep = '\0';
|
||||
|
|
@ -873,15 +864,39 @@ static int qe_cfg_call(QEmacsDataSource *ds, QEValue *sp, CmdDef *d) {
|
|||
args[i].n = (int)(intptr_t)d->val;
|
||||
continue;
|
||||
case CMD_ARG_STRINGVAL:
|
||||
/* CG: kludge for xxx-mode functions and named kbd macros */
|
||||
args[i].p = prompt;
|
||||
/* CG: kludge for xxx-mode functions and named kbd macros,
|
||||
must be last argument */
|
||||
args[i].p = cas.prompt;
|
||||
continue;
|
||||
case CMD_ARG_INT | CMD_ARG_USE_ARGVAL: /* XXX: ui should always be last */
|
||||
case CMD_ARG_INT | CMD_ARG_USE_ARGVAL:
|
||||
if (ds->tok == ')') {
|
||||
args[i].n = NO_ARG;
|
||||
continue;
|
||||
}
|
||||
args_type[i] &= ~CMD_ARG_USE_ARGVAL;
|
||||
break;
|
||||
case CMD_ARG_INT | CMD_ARG_USE_MARK:
|
||||
if (ds->tok == ')') {
|
||||
args[i].n = s->b->mark;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case CMD_ARG_INT | CMD_ARG_USE_POINT:
|
||||
if (ds->tok == ')') {
|
||||
args[i].n = s->offset;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case CMD_ARG_INT | CMD_ARG_USE_ZERO:
|
||||
if (ds->tok == ')') {
|
||||
args[i].n = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case CMD_ARG_INT | CMD_ARG_USE_BSIZE:
|
||||
if (ds->tok == ')') {
|
||||
args[i].n = s->b->total_size;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -901,7 +916,7 @@ static int qe_cfg_call(QEmacsDataSource *ds, QEValue *sp, CmdDef *d) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
switch (args_type[i]) {
|
||||
switch (args_type[i] & CMD_ARG_TYPE_MASK) {
|
||||
case CMD_ARG_INT:
|
||||
qe_cfg_tonum(ds, sp); // XXX: should complain about type mismatch?
|
||||
args[i].n = sp->u.value;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue