Fix eval_region
* factorize evaluation result handling * make QEValue.type signed to handle TOK_ERR and TOK_EOF * extract buffer contents as UTF-8 * eval-region and eval-buffer take universal argument to insert expression result instead of showing as message
This commit is contained in:
parent
bf0c938d19
commit
e25667c577
2 changed files with 88 additions and 72 deletions
11
qe.h
11
qe.h
|
|
@ -2,7 +2,7 @@
|
|||
* QEmacs, tiny but powerful multimode editor
|
||||
*
|
||||
* Copyright (c) 2000-2001 Fabrice Bellard.
|
||||
* Copyright (c) 2000-2022 Charlie Gordon.
|
||||
* Copyright (c) 2000-2023 Charlie Gordon.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -1612,8 +1612,9 @@ void set_tty_charset(const char *name);
|
|||
/* values */
|
||||
|
||||
typedef struct QEValue {
|
||||
unsigned int type : 16; // value type: TOK_VOID, TOK_NUMBER, TOK_CHAR, TOK_STRING
|
||||
// should also have TOK_WINDOW, TOK_BUFFER, TOK_MODE...
|
||||
int type : 16; // value type: TOK_VOID, TOK_NUMBER, TOK_CHAR, TOK_STRING
|
||||
// also errors: TOK_ERR?
|
||||
// should also have TOK_WINDOW, TOK_BUFFER, TOK_MODE...
|
||||
unsigned int alloc : 8; // u.str should be freed
|
||||
unsigned int flags : 8;
|
||||
// XXX: could have flags for owning allocated block pointed to by `str`
|
||||
|
|
@ -1699,8 +1700,8 @@ static inline void qe_cfg_swap(QEValue *sp, QEValue *sp1) {
|
|||
|
||||
int parse_config_file(EditState *s, const char *filename);
|
||||
void do_eval_expression(EditState *s, const char *expression, int argval);
|
||||
void do_eval_region(EditState *s); /* should pass actual offsets */
|
||||
void do_eval_buffer(EditState *s);
|
||||
void do_eval_region(EditState *s, int argval); /* should pass actual offsets */
|
||||
void do_eval_buffer(EditState *s, int argval);
|
||||
#ifdef CONFIG_SESSION
|
||||
extern int use_session_file;
|
||||
int qe_load_session(EditState *s);
|
||||
|
|
|
|||
149
qescript.c
149
qescript.c
|
|
@ -50,9 +50,10 @@ enum {
|
|||
TOK_EOF = -1, TOK_ERR = -2, TOK_VOID__ = 0,
|
||||
TOK_NUMBER__ = 128, TOK_STRING__, TOK_CHAR__, TOK_ID__, TOK_IF, TOK_ELSE,
|
||||
#ifndef CONFIG_TINY
|
||||
TOK_MUL_EQ, TOK_DIV_EQ, TOK_MOD_EQ, TOK_ADD_EQ, TOK_SUB_EQ, TOK_SHL_EQ, TOK_SHR_EQ,
|
||||
TOK_AND_EQ, TOK_XOR_EQ, TOK_OR_EQ,
|
||||
TOK_EQ, TOK_NE, TOK_SHL, TOK_SHR, TOK_LE, TOK_GE, TOK_INC, TOK_DEC, TOK_LOR, TOK_LAND,
|
||||
TOK_MUL_EQ, TOK_DIV_EQ, TOK_MOD_EQ, TOK_ADD_EQ, TOK_SUB_EQ,
|
||||
TOK_SHL_EQ, TOK_SHR_EQ, TOK_AND_EQ, TOK_XOR_EQ, TOK_OR_EQ,
|
||||
TOK_EQ, TOK_NE, TOK_SHL, TOK_SHR, TOK_LE, TOK_GE,
|
||||
TOK_INC, TOK_DEC, TOK_LOR, TOK_LAND,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -1235,6 +1236,58 @@ static int qe_parse_script(EditState *s, QEmacsDataSource *ds) {
|
|||
return sp->type;
|
||||
}
|
||||
|
||||
static void qe_cfg_postprocess(EditState *s, QEmacsDataSource *ds, int argval) {
|
||||
#ifndef CONFIG_TINY
|
||||
QEValue *sp = &ds->stack[0];
|
||||
char buf[64];
|
||||
int len;
|
||||
|
||||
if (argval == NO_ARG)
|
||||
argval = 0;
|
||||
|
||||
if (argval > 0 && check_read_only(s))
|
||||
return;
|
||||
|
||||
if (!qe_cfg_getvalue(ds, sp)) {
|
||||
switch (sp->type) {
|
||||
case TOK_VOID:
|
||||
break;
|
||||
case TOK_NUMBER:
|
||||
if (argval <= 0) {
|
||||
put_status(s, "-> %lld %llx", sp->u.value, sp->u.value);
|
||||
} else {
|
||||
if (argval == 16)
|
||||
len = snprintf(buf, sizeof buf, "%llx", sp->u.value);
|
||||
else
|
||||
len = snprintf(buf, sizeof buf, "%lld", sp->u.value);
|
||||
s->offset += eb_insert_utf8_buf(s->b, s->offset, buf, len);
|
||||
}
|
||||
break;
|
||||
case TOK_STRING:
|
||||
if (argval <= 0) {
|
||||
/* XXX: should optionally unparse string */
|
||||
put_status(s, "-> \"%s\"", sp->u.str);
|
||||
} else {
|
||||
s->offset += eb_insert_utf8_buf(s->b, s->offset, sp->u.str, sp->len);
|
||||
}
|
||||
break;
|
||||
case TOK_CHAR:
|
||||
len = utf8_encode(buf, (char32_t)sp->u.value);
|
||||
if (argval <= 0) {
|
||||
/* XXX: should optionally unparse character */
|
||||
put_status(s, "-> '%.*s'", len, buf);
|
||||
} else {
|
||||
s->offset += eb_insert_utf8_buf(s->b, s->offset, buf, len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
put_error(s, "unexpected value type: %d", sp->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_eval_expression(EditState *s, const char *expression, int argval)
|
||||
{
|
||||
QEmacsDataSource ds;
|
||||
|
|
@ -1245,62 +1298,17 @@ void do_eval_expression(EditState *s, const char *expression, int argval)
|
|||
if (qe_parse_script(s, &ds) == TOK_ERR) {
|
||||
put_error(s, "evaluation error");
|
||||
} else {
|
||||
#ifndef CONFIG_TINY
|
||||
QEValue *sp = &ds.stack[0];
|
||||
char buf[64];
|
||||
int len;
|
||||
|
||||
if (argval != NO_ARG && check_read_only(s))
|
||||
return;
|
||||
|
||||
if (!qe_cfg_getvalue(&ds, sp)) {
|
||||
switch (sp->type) {
|
||||
case TOK_VOID:
|
||||
break;
|
||||
case TOK_NUMBER:
|
||||
if (argval == NO_ARG) {
|
||||
put_status(s, "-> %lld %llx", sp->u.value, sp->u.value);
|
||||
} else {
|
||||
if (argval == 16)
|
||||
len = snprintf(buf, sizeof buf, "%llx", sp->u.value);
|
||||
else
|
||||
len = snprintf(buf, sizeof buf, "%lld", sp->u.value);
|
||||
s->offset += eb_insert_utf8_buf(s->b, s->offset, buf, len);
|
||||
}
|
||||
break;
|
||||
case TOK_STRING:
|
||||
if (argval == NO_ARG) {
|
||||
/* XXX: should optionally unparse string */
|
||||
put_status(s, "-> \"%s\"", sp->u.str);
|
||||
} else {
|
||||
s->offset += eb_insert_utf8_buf(s->b, s->offset, sp->u.str, sp->len);
|
||||
}
|
||||
break;
|
||||
case TOK_CHAR:
|
||||
len = utf8_encode(buf, (char32_t)sp->u.value);
|
||||
if (argval == NO_ARG) {
|
||||
/* XXX: should optionally unparse character */
|
||||
put_status(s, "-> '%.*s'", len, buf);
|
||||
} else {
|
||||
s->offset += eb_insert_utf8_buf(s->b, s->offset, buf, len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
put_error(s, "unexpected value type: %d", sp->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
qe_cfg_postprocess(s, &ds, argval);
|
||||
}
|
||||
qe_cfg_release(&ds);
|
||||
}
|
||||
|
||||
#define MAX_SCRIPT_LENGTH (128 * 1024 - 1)
|
||||
|
||||
static int do_eval_buffer_region(EditState *s, int start, int stop) {
|
||||
static int do_eval_buffer_region(EditState *s, int start, int stop, int argval) {
|
||||
QEmacsDataSource ds;
|
||||
char *buf;
|
||||
int length, res;
|
||||
int length, res = 0;
|
||||
|
||||
qe_cfg_init(&ds);
|
||||
|
||||
|
|
@ -1309,32 +1317,39 @@ static int do_eval_buffer_region(EditState *s, int start, int stop) {
|
|||
start = stop;
|
||||
stop = tmp;
|
||||
}
|
||||
start = max_offset(start, 0);
|
||||
stop = clamp_offset(stop, start, s->b->total_size);
|
||||
length = stop - start;
|
||||
/* extract region as UTF-8 with a size limit */
|
||||
length = eb_get_region_content_size(s->b, start, stop);
|
||||
if (length > MAX_SCRIPT_LENGTH || !(buf = qe_malloc_array(char, length + 1))) {
|
||||
put_error(s, "buffer too large");
|
||||
return -1;
|
||||
}
|
||||
/* assuming compatible encoding */
|
||||
length = eb_read(s->b, start, buf, length);
|
||||
buf[length] = '\0';
|
||||
length = eb_get_region_contents(s->b, start, stop, buf, length + 1, 0);
|
||||
ds.buf = ds.allocated_buf = buf;
|
||||
ds.filename = s->b->name;
|
||||
res = qe_parse_script(s, &ds);
|
||||
if (qe_parse_script(s, &ds) == TOK_ERR) {
|
||||
put_error(s, "evaluation error");
|
||||
res = 1;
|
||||
} else {
|
||||
if (argval != NO_ARG && !check_read_only(s)) {
|
||||
// replace region with script result
|
||||
// assuming script did not move point, nor modify buffer
|
||||
eb_delete_range(s->b, start, stop);
|
||||
}
|
||||
qe_cfg_postprocess(s, &ds, argval);
|
||||
}
|
||||
qe_cfg_release(&ds);
|
||||
do_refresh(s);
|
||||
//do_refresh(s);
|
||||
return res;
|
||||
}
|
||||
|
||||
void do_eval_region(EditState *s) {
|
||||
void do_eval_region(EditState *s, int argval) {
|
||||
s->region_style = 0; /* deactivate region hilite */
|
||||
|
||||
do_eval_buffer_region(s, s->b->mark, s->offset);
|
||||
do_eval_buffer_region(s, s->b->mark, s->offset, argval);
|
||||
}
|
||||
|
||||
void do_eval_buffer(EditState *s) {
|
||||
do_eval_buffer_region(s, 0, s->b->total_size);
|
||||
void do_eval_buffer(EditState *s, int argval) {
|
||||
do_eval_buffer_region(s, 0, s->b->total_size, argval);
|
||||
}
|
||||
|
||||
int parse_config_file(EditState *s, const char *filename) {
|
||||
|
|
@ -1386,12 +1401,12 @@ static const CmdDef parser_commands[] = {
|
|||
"s{Eval: }[.symbol]|expression|"
|
||||
"P")
|
||||
/* XXX: should take region as argument, implicit from keyboard */
|
||||
CMD0( "eval-region", "M-C-z",
|
||||
CMD2( "eval-region", "M-C-z",
|
||||
"Evaluate qemacs expressions in a region",
|
||||
do_eval_region)
|
||||
CMD0( "eval-buffer", "",
|
||||
do_eval_region, ESi, "P")
|
||||
CMD2( "eval-buffer", "",
|
||||
"Evaluate qemacs expressions in the buffer",
|
||||
do_eval_buffer)
|
||||
do_eval_buffer, ESi, "P")
|
||||
};
|
||||
|
||||
static int parser_init(void) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue