diff options
Diffstat (limited to 'src/core-commands.c')
| -rw-r--r-- | src/core-commands.c | 184 |
1 files changed, 120 insertions, 64 deletions
diff --git a/src/core-commands.c b/src/core-commands.c index 81d5869..6c4ab58 100644 --- a/src/core-commands.c +++ b/src/core-commands.c @@ -52,6 +52,7 @@ static teco_state_t *teco_state_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error); static teco_state_t *teco_state_ctlc_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error); +static teco_state_t *teco_state_endcond(teco_machine_main_t *ctx, const gchar *cmd, GError **error); /** * Translate buffer range arguments from the expression stack to @@ -72,7 +73,8 @@ static teco_state_t *teco_state_ctlc_control_input(teco_machine_main_t *ctx, gun * But it needs to discern between invalid ranges and other errors. */ gboolean -teco_get_range_args(const gchar *cmd, gsize *from_ret, gsize *len_ret, GError **error) +teco_get_range_args(const gchar *cmd, teco_int_t *from_glyphs_ret, gsize *from_ret, + teco_int_t *len_glyphs_ret, gsize *len_ret, GError **error) { gssize from, len; /* in bytes */ @@ -99,15 +101,27 @@ teco_get_range_args(const gchar *cmd, gsize *from_ret, gsize *len_ret, GError ** from += len; len *= -1; } + + if (from_glyphs_ret) + *from_glyphs_ret = teco_interface_bytes2glyphs_absdot(from); + if (len_glyphs_ret) + *len_glyphs_ret = teco_interface_bytes2glyphs_absdot(from+len); } else { - gssize to = teco_interface_glyphs2bytes(teco_expressions_pop_num(0)); - from = teco_interface_glyphs2bytes(teco_expressions_pop_num(0)); + teco_int_t to_glyphs = teco_expressions_pop_num(0); + gssize to = teco_interface_glyphs2bytes_absdot(to_glyphs); + teco_int_t from_glyphs = teco_expressions_pop_num(0); + from = teco_interface_glyphs2bytes_absdot(from_glyphs); len = to - from; if (len < 0 || from < 0 || to < 0) { teco_error_range_set(error, cmd); return FALSE; } + + if (from_glyphs_ret) + *from_glyphs_ret = from_glyphs; + if (len_glyphs_ret) + *len_glyphs_ret = to_glyphs - from_glyphs; } *from_ret = from; @@ -199,8 +213,7 @@ teco_state_start_dot(teco_machine_main_t *ctx, GError **error) { if (!teco_expressions_eval(FALSE, error)) return; - sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); - teco_expressions_push(teco_interface_bytes2glyphs(pos)); + teco_expressions_push(teco_current_doc_get_dot()); } /*$ Z size @@ -217,7 +230,7 @@ teco_state_start_zed(teco_machine_main_t *ctx, GError **error) if (!teco_expressions_eval(FALSE, error)) return; sptr_t pos = teco_interface_ssm(SCI_GETLENGTH, 0, 0); - teco_expressions_push(teco_interface_bytes2glyphs(pos)); + teco_expressions_push(teco_interface_bytes2glyphs_absdot(pos)); } /*$ H @@ -235,7 +248,7 @@ teco_state_start_range(teco_machine_main_t *ctx, GError **error) return; teco_expressions_push(0); sptr_t pos = teco_interface_ssm(SCI_GETLENGTH, 0, 0); - teco_expressions_push(teco_interface_bytes2glyphs(pos)); + teco_expressions_push(teco_interface_bytes2glyphs_absdot(pos)); } /*$ \[rs] @@ -267,8 +280,7 @@ teco_state_start_backslash(teco_machine_main_t *ctx, GError **error) g_assert(*str != '\0'); gsize len = strlen(str); - sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); - teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(pos); + teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot(); /* * We can assume that `len` is already in glyphs, * i.e. formatted numbers will never use multi-byte/Unicode characters. @@ -276,6 +288,8 @@ teco_state_start_backslash(teco_machine_main_t *ctx, GError **error) teco_undo_int(teco_ranges[0].to) = teco_ranges[0].from + len; teco_undo_guint(teco_ranges_count) = 1; + teco_current_doc_set_dot(teco_ranges[0].to); + teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0); teco_interface_ssm(SCI_ADDTEXT, len, (sptr_t)str); teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0); @@ -563,6 +577,12 @@ teco_state_start_cmdline_push(teco_machine_main_t *ctx, GError **error) * A undo action should always have been generated. */ undo__teco_interface_ssm(SCI_UNDO, 0, 0); + + /* + * FIXME: If we would maintain dot in the command line, + * it could simply be copied. + */ + teco_current_doc_set_dot(teco_interface_bytes2glyphs_rel(0, 0, teco_cmdline.pc)); } static void @@ -601,7 +621,8 @@ teco_state_start_cmdline_pop(teco_machine_main_t *ctx, GError **error) * immediately after dot. * - If <n> is -1, return the <code> of the character * immediately preceding dot, ecetera. - * - If <n> is omitted, the sign prefix is implied. + * - If <n> is omitted, 0 is implied. + * However \(lq-A\(rq is equivalent to \(lq-1A\(rq. * * If the position of the queried character is off-page, * the command will return -1. @@ -610,15 +631,22 @@ teco_state_start_cmdline_pop(teco_machine_main_t *ctx, GError **error) * -2 is returned. * Incomplete byte sequences are returned as -3. */ +/* + * NOTE: `A` without arguments is the Append I/O + * command in TECO-11. It doesn't make sense in our case. + */ static void teco_state_start_get(teco_machine_main_t *ctx, GError **error) { - teco_int_t v; - if (!teco_expressions_pop_num_calc(&v, teco_num_sign, error)) + teco_int_t v = 0; + + if (!teco_expressions_eval(FALSE, error)) + return; + if ((teco_expressions_args() || teco_num_sign < 0) && + !teco_expressions_pop_num_calc(&v, teco_num_sign, error)) return; - sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); - gssize get_pos = teco_interface_glyphs2bytes_relative(pos, v); + gssize get_pos = teco_interface_glyphs2bytes_reldot(v); sptr_t len = teco_interface_ssm(SCI_GETLENGTH, 0, 0); teco_expressions_push(get_pos < 0 || get_pos == len @@ -732,7 +760,8 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error) if (teco_is_noop(chr)) { if (ctx->flags.modifier_at || (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) { - teco_error_modifier_set(error, chr); + gchar cmd[] = {chr, '\0'}; + teco_error_modifier_set(error, cmd); return NULL; } return &teco_state_start; @@ -758,7 +787,8 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error) case '0' ... '9': if (ctx->flags.modifier_at || (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) { - teco_error_modifier_set(error, chr); + gchar cmd[] = {chr, '\0'}; + teco_error_modifier_set(error, cmd); return NULL; } if (ctx->flags.mode == TECO_MODE_NORMAL) @@ -817,7 +847,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error) case '|': if (ctx->flags.modifier_at || (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) { - teco_error_modifier_set(error, '|'); + teco_error_modifier_set(error, "|"); return NULL; } if (ctx->parent.must_undo) @@ -829,29 +859,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error) ctx->flags.mode = TECO_MODE_PARSE_ONLY_COND; return &teco_state_start; - case '\'': - if (ctx->flags.modifier_at || - (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) { - teco_error_modifier_set(error, '\''); - return NULL; - } - switch (ctx->flags.mode) { - case TECO_MODE_PARSE_ONLY_COND: - case TECO_MODE_PARSE_ONLY_COND_FORCE: - if (!ctx->nest_level) { - if (ctx->parent.must_undo) - teco_undo_flags(ctx->flags); - ctx->flags.mode = TECO_MODE_NORMAL; - } else { - if (ctx->parent.must_undo) - teco_undo_gint(ctx->nest_level); - ctx->nest_level--; - } - break; - default: - break; - } - return &teco_state_start; + case '\'': return teco_state_endcond(ctx, "'", error); /* * Word movement and deletion commands. @@ -877,7 +885,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error) */ case '@': if (ctx->flags.modifier_at) { - teco_error_modifier_set(error, '@'); + teco_error_modifier_set(error, "@"); return NULL; } /* @@ -895,7 +903,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error) if (ctx->flags.mode > TECO_MODE_NORMAL) return &teco_state_start; if (ctx->flags.modifier_colon >= 2) { - teco_error_modifier_set(error, ':'); + teco_error_modifier_set(error, ":"); return NULL; } if (ctx->parent.must_undo) @@ -1078,6 +1086,10 @@ teco_state_fcommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error ['|'] = {&teco_state_start, teco_state_fcommand_cond_else} }; + switch (chr) { + case '"': return teco_state_endcond(ctx, "F\"", error); + } + return teco_machine_main_transition_input(ctx, transitions, G_N_ELEMENTS(transitions), teco_ascii_toupper(chr), error); } @@ -1297,6 +1309,35 @@ TECO_DEFINE_STATE_COMMAND(teco_state_condcommand, .input_cb = (teco_state_input_cb_t)teco_state_condcommand_input ); +static teco_state_t * +teco_state_endcond(teco_machine_main_t *ctx, const gchar *cmd, GError **error) +{ + if (ctx->flags.modifier_at || + (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) { + teco_error_modifier_set(error, cmd); + return NULL; + } + + switch (ctx->flags.mode) { + case TECO_MODE_PARSE_ONLY_COND: + case TECO_MODE_PARSE_ONLY_COND_FORCE: + if (!ctx->nest_level) { + if (ctx->parent.must_undo) + teco_undo_flags(ctx->flags); + ctx->flags.mode = TECO_MODE_NORMAL; + } else { + if (ctx->parent.must_undo) + teco_undo_gint(ctx->nest_level); + ctx->nest_level--; + } + break; + default: + break; + } + + return &teco_state_start; +} + /*$ ^_ negate * n^_ -> ~n -- Binary negation * @@ -1345,8 +1386,7 @@ teco_state_control_octal(teco_machine_main_t *ctx, GError **error) { teco_qreg_t *qreg = ctx->qreg_table_locals->radix; assert(qreg != NULL); - if (!qreg->vtable->undo_set_integer(qreg, error) || - !qreg->vtable->set_integer(qreg, 8, NULL)) + if (!qreg->vtable->set_integer(qreg, 8, NULL)) return; } @@ -1358,8 +1398,7 @@ teco_state_control_decimal(teco_machine_main_t *ctx, GError **error) { teco_qreg_t *qreg = ctx->qreg_table_locals->radix; assert(qreg != NULL); - if (!qreg->vtable->undo_set_integer(qreg, error) || - !qreg->vtable->set_integer(qreg, 10, NULL)) + if (!qreg->vtable->set_integer(qreg, 10, NULL)) return; } @@ -1390,8 +1429,7 @@ teco_state_control_radix(teco_machine_main_t *ctx, GError **error) return; teco_expressions_push(radix); } else { - if (!qreg->vtable->undo_set_integer(qreg, error) || - !qreg->vtable->set_integer(qreg, teco_expressions_pop_num(0), error)) + if (!qreg->vtable->set_integer(qreg, teco_expressions_pop_num(0), error)) return; } } @@ -1444,14 +1482,9 @@ teco_state_control_glyphs2bytes(teco_machine_main_t *ctx, GError **error) res = teco_interface_ssm(colon_modified ? SCI_GETLENGTH : SCI_GETCURRENTPOS, 0, 0); } else { teco_int_t pos = teco_expressions_pop_num(0); - if (colon_modified) { - /* teco_interface_bytes2glyphs() does not check addresses */ - res = 0 <= pos && pos <= teco_interface_ssm(SCI_GETLENGTH, 0, 0) - ? teco_interface_bytes2glyphs(pos) : -1; - } else { - /* negative values for invalid indexes are passed down. */ - res = teco_interface_glyphs2bytes(pos); - } + /* negative values for invalid indexes are passed down. */ + res = colon_modified ? teco_interface_bytes2glyphs_absdot(pos) + : teco_interface_glyphs2bytes_absdot(pos); } teco_expressions_push(res); @@ -2671,7 +2704,7 @@ teco_state_ecommand_encoding(teco_machine_main_t *ctx, GError **error) teco_int_t dot_glyphs = 0; if (colon_modified) { sptr_t dot_bytes = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); - dot_glyphs = teco_interface_bytes2glyphs(dot_bytes); + dot_glyphs = teco_current_doc_get_dot(); /* * Convert buffer to new codepage. @@ -2719,7 +2752,7 @@ teco_state_ecommand_encoding(teco_machine_main_t *ctx, GError **error) teco_interface_ssm(SCI_SETCODEPAGE, SC_CP_UTF8, 0); /* * UTF-8 documents strictly require the line character index. - * See teco_view_glyphs2bytes() and teco_view_bytes2glyphs(). + * See teco_view_glyphs2bytes_unicode() and teco_view_bytes2glyphs_unicode(). */ g_assert(!(teco_interface_ssm(SCI_GETLINECHARACTERINDEX, 0, 0) & SC_LINECHARACTERINDEX_UTF32)); @@ -2763,13 +2796,18 @@ teco_state_ecommand_encoding(teco_machine_main_t *ctx, GError **error) teco_interface_ssm(SCI_SETCODEPAGE, 0, 0); } - if (colon_modified) + if (colon_modified) { /* * Only now, it will be safe to recalculate dot in the new encoding. * If the new codepage is UTF-8, the line character index will be * ready only now. */ - teco_interface_ssm(SCI_GOTOPOS, teco_interface_glyphs2bytes(dot_glyphs), 0); + teco_interface_ssm(SCI_GOTOPOS, teco_interface_glyphs2bytes_rel(0, 0, dot_glyphs), 0); + } else { + /* recalculate dot */ + sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); + teco_current_doc_set_dot(teco_interface_bytes2glyphs_rel(0, 0, pos)); + } } /*$ EO version @@ -2869,6 +2907,7 @@ teco_state_ecommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error /* * Simple Transitions */ + ['*'] = {&teco_state_save_cmdline}, ['%'] = {&teco_state_epctcommand, .modifier_at = TRUE}, ['B'] = {&teco_state_edit_file, @@ -2928,8 +2967,7 @@ teco_state_insert_initial(teco_machine_main_t *ctx, GError **error) if (ctx->flags.mode > TECO_MODE_NORMAL) return TRUE; - sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); - teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(pos); + teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot(); teco_undo_guint(teco_ranges_count) = 1; /* @@ -2942,8 +2980,10 @@ teco_state_insert_initial(teco_machine_main_t *ctx, GError **error) if (!teco_expressions_eval(FALSE, error)) return FALSE; guint args = teco_expressions_args(); - if (!args) + if (!args) { + teco_undo_int(teco_ranges[0].to) = teco_ranges[0].from; return TRUE; + } if (teco_interface_ssm(SCI_GETCODEPAGE, 0, 0) == SC_CP_UTF8) { /* detect possible errors before introducing side effects */ @@ -2986,6 +3026,9 @@ teco_state_insert_initial(teco_machine_main_t *ctx, GError **error) for (gint i = 0; i < args; i++) teco_expressions_pop_num(0); + /* this way we remember how many numeric arguments were given */ + teco_undo_int(teco_ranges[0].to) = teco_ranges[0].from + args; + return TRUE; } @@ -3013,8 +3056,15 @@ teco_state_insert_done(teco_machine_main_t *ctx, teco_string_t str, GError **err if (ctx->flags.mode > TECO_MODE_NORMAL) return &teco_state_start; + /* + * NOTE: teco_interface_bytes2glyphs_reldot() would count relative to + * dot, which is still invalid. + */ sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0); - teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs(pos); + teco_int_t to = teco_interface_bytes2glyphs_rel(teco_ranges[0].to, pos-str.len, str.len); + teco_undo_int(teco_ranges[0].to) = to; + teco_current_doc_set_dot(to); + return &teco_state_start; } @@ -3053,12 +3103,18 @@ teco_state_insert_indent_initial(teco_machine_main_t *ctx, GError **error) teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0); if (teco_interface_ssm(SCI_GETUSETABS, 0, 0)) { teco_interface_ssm(SCI_ADDTEXT, 1, (sptr_t)"\t"); + + /* teco_state_insert_done() expects this */ + teco_undo_int(teco_ranges[0].to)++; } else { gint len = teco_interface_ssm(SCI_GETTABWIDTH, 0, 0); len -= teco_interface_ssm(SCI_GETCOLUMN, teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), 0) % len; + /* teco_state_insert_done() expects this */ + teco_undo_int(teco_ranges[0].to) += len; + gchar space = ' '; while (len-- > 0) teco_interface_ssm(SCI_ADDTEXT, 1, (sptr_t)&space); |
