aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core-commands.c55
-rw-r--r--src/expressions.c25
-rw-r--r--src/expressions.h15
-rw-r--r--src/main.c7
-rw-r--r--src/parser.c4
-rw-r--r--src/qreg-commands.c5
-rw-r--r--src/qreg.c43
-rw-r--r--src/qreg.h7
-rw-r--r--src/search.c27
9 files changed, 144 insertions, 44 deletions
diff --git a/src/core-commands.c b/src/core-commands.c
index ca0245b..ba7aaa8 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -196,7 +196,8 @@ teco_state_start_backslash(teco_machine_main_t *ctx, GError **error)
return;
gchar buffer[TECO_EXPRESSIONS_FORMAT_LEN];
- gchar *str = teco_expressions_format(buffer, value);
+ gchar *str = teco_expressions_format(buffer, value,
+ ctx->qreg_table_locals->radix);
g_assert(*str != '\0');
teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
@@ -207,6 +208,12 @@ teco_state_start_backslash(teco_machine_main_t *ctx, GError **error)
if (teco_current_doc_must_undo())
undo__teco_interface_ssm(SCI_UNDO, 0, 0);
} else {
+ teco_qreg_t *qreg = ctx->qreg_table_locals->radix;
+ assert(qreg != NULL);
+ teco_int_t radix;
+ if (!qreg->vtable->get_integer(qreg, &radix, error))
+ return;
+
uptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
gchar c = (gchar)teco_interface_ssm(SCI_GETCHARAT, pos, 0);
teco_int_t v = 0;
@@ -219,11 +226,11 @@ teco_state_start_backslash(teco_machine_main_t *ctx, GError **error)
for (;;) {
c = teco_ascii_toupper((gchar)teco_interface_ssm(SCI_GETCHARAT, pos, 0));
- if (c >= '0' && c <= '0' + MIN(teco_radix, 10) - 1)
- v = (v*teco_radix) + (c - '0');
+ if (c >= '0' && c <= '0' + MIN(radix, 10) - 1)
+ v = (v*radix) + (c - '0');
else if (c >= 'A' &&
- c <= 'A' + MIN(teco_radix - 10, 26) - 1)
- v = (v*teco_radix) + 10 + (c - 'A');
+ c <= 'A' + MIN(radix - 10, 26) - 1)
+ v = (v*radix) + 10 + (c - 'A');
else
break;
@@ -1164,7 +1171,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
*/
case '0' ... '9':
if (ctx->mode == TECO_MODE_NORMAL)
- teco_expressions_add_digit(chr);
+ teco_expressions_add_digit(chr, ctx->qreg_table_locals->radix);
return &teco_state_start;
case '*':
@@ -1710,7 +1717,11 @@ teco_state_control_exit(teco_machine_main_t *ctx, GError **error)
static void
teco_state_control_octal(teco_machine_main_t *ctx, GError **error)
{
- teco_set_radix(8);
+ 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))
+ return;
}
/*$ ^D decimal
@@ -1719,7 +1730,11 @@ teco_state_control_octal(teco_machine_main_t *ctx, GError **error)
static void
teco_state_control_decimal(teco_machine_main_t *ctx, GError **error)
{
- teco_set_radix(10);
+ 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))
+ return;
}
/*$ ^R radix
@@ -1729,19 +1744,35 @@ teco_state_control_decimal(teco_machine_main_t *ctx, GError **error)
* Set current radix to arbitrary value <radix>.
* If <radix> is omitted, the command instead
* returns the current radix.
+ *
+ * An alternative way to access the radix is via the "^R" local Q-Register.
+ * Consequently, the radix is local to the current macro invocation frame,
+ * unless the macro call was colon-modified.
*/
static void
teco_state_control_radix(teco_machine_main_t *ctx, GError **error)
{
if (!teco_expressions_eval(FALSE, error))
return;
+
+ teco_qreg_t *qreg = ctx->qreg_table_locals->radix;
+ assert(qreg != NULL);
+ teco_int_t radix;
+
if (!teco_expressions_args()) {
- teco_expressions_push(teco_radix);
+ if (!qreg->vtable->get_integer(qreg, &radix, error))
+ return;
+ teco_expressions_push(radix);
} else {
- teco_int_t v;
- if (!teco_expressions_pop_num_calc(&v, 0, error))
+ /*
+ * FIXME: We should restrict the allowed values.
+ * 0^R 23\ crashes for instance.
+ * The ^R register should consequently also be "special".
+ */
+ if (!teco_expressions_pop_num_calc(&radix, 0, error) ||
+ !qreg->vtable->undo_set_integer(qreg, error) ||
+ !qreg->vtable->set_integer(qreg, radix, error))
return;
- teco_set_radix(v);
}
}
diff --git a/src/expressions.c b/src/expressions.c
index ee6b4dc..25213e9 100644
--- a/src/expressions.c
+++ b/src/expressions.c
@@ -23,6 +23,7 @@
#include "sciteco.h"
#include "error.h"
#include "undo.h"
+#include "qreg.h"
#include "expressions.h"
/*
@@ -57,7 +58,6 @@ teco_expressions_precedence(teco_operator_t op)
}
gint teco_num_sign = 1;
-gint teco_radix = 10;
void
teco_expressions_push_int(teco_int_t number)
@@ -114,12 +114,20 @@ teco_expressions_pop_num_calc(teco_int_t *ret, teco_int_t imply, GError **error)
}
void
-teco_expressions_add_digit(gunichar digit)
+teco_expressions_add_digit(gunichar digit, teco_qreg_t *qreg)
{
+ /*
+ * FIXME: We could just access qreg->integer here since
+ * we can assume that "^R" is a plain register.
+ */
+ assert(qreg != NULL);
+ teco_int_t radix = 10;
+ qreg->vtable->get_integer(qreg, &radix, NULL);
+
teco_int_t n = teco_expressions_args() > 0 ? teco_expressions_pop_num(0) : 0;
/* use g_unichar_digit_value()? */
- teco_expressions_push(n*teco_radix + (n < 0 ? -1 : 1)*((gint)digit - '0'));
+ teco_expressions_push(n*radix + (n < 0 ? -1 : 1)*((gint)digit - '0'));
}
void
@@ -378,21 +386,26 @@ teco_expressions_clear(void)
* @param buffer The output buffer of at least TECO_EXPRESSIONS_FORMAT_LEN characters.
* The output string will be null-terminated.
* @param number The number to format.
+ * @param table The local Q-Register table that contains the appropriate radix register (^R).
* @return A pointer into buffer to the beginning of the formatted number.
*/
gchar *
-teco_expressions_format(gchar *buffer, teco_int_t number)
+teco_expressions_format(gchar *buffer, teco_int_t number, teco_qreg_t *qreg)
{
+ assert(qreg != NULL);
+ teco_int_t radix = 10;
+ qreg->vtable->get_integer(qreg, &radix, NULL);
+
gchar *p = buffer + TECO_EXPRESSIONS_FORMAT_LEN;
teco_int_t v = ABS(number);
*--p = '\0';
do {
- *--p = '0' + (v % teco_radix);
+ *--p = '0' + (v % radix);
if (*p > '9')
*p += 'A' - '9' - 1;
- } while ((v /= teco_radix));
+ } while ((v /= radix));
if (number < 0)
*--p = '-';
diff --git a/src/expressions.h b/src/expressions.h
index 68d8ddb..caea1d7 100644
--- a/src/expressions.h
+++ b/src/expressions.h
@@ -19,6 +19,7 @@
#include <glib.h>
#include "sciteco.h"
+#include "qreg.h"
#include "undo.h"
/**
@@ -101,14 +102,6 @@ teco_set_num_sign(gint sign)
teco_undo_gint(teco_num_sign) = sign;
}
-extern gint teco_radix;
-
-static inline void
-teco_set_radix(gint r)
-{
- teco_undo_gint(teco_radix) = r;
-}
-
void teco_expressions_push_int(teco_int_t number);
/** Push characters of a C-string. */
@@ -123,7 +116,7 @@ teco_int_t teco_expressions_peek_num(guint index);
teco_int_t teco_expressions_pop_num(guint index);
gboolean teco_expressions_pop_num_calc(teco_int_t *ret, teco_int_t imply, GError **error);
-void teco_expressions_add_digit(gunichar digit);
+void teco_expressions_add_digit(gunichar digit, teco_qreg_t *radix);
void teco_expressions_push_op(teco_operator_t op);
gboolean teco_expressions_push_calc(teco_operator_t op, GError **error);
@@ -155,8 +148,8 @@ gboolean teco_expressions_brace_close(GError **error);
void teco_expressions_clear(void);
-/** Maximum size required to format a number if teco_radix == 2 */
+/** Maximum size required to format a number if radix == 2 */
#define TECO_EXPRESSIONS_FORMAT_LEN \
(1 + sizeof(teco_int_t)*8 + 1)
-gchar *teco_expressions_format(gchar *buffer, teco_int_t number);
+gchar *teco_expressions_format(gchar *buffer, teco_int_t number, teco_qreg_t *radix);
diff --git a/src/main.c b/src/main.c
index 4d0e4e9..40191b4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -390,6 +390,11 @@ main(int argc, char **argv)
teco_qreg_view = teco_view_new();
teco_view_setup(teco_qreg_view);
+ /*
+ * FIXME: "_" and "-" should perhaps be in the local Q-Reg table, so you don't
+ * have to back them up on the Q-Reg stack in portable macros.
+ * DEC TECO has them in the global table, though.
+ */
/* search string and status register */
teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_plain_new("_", 1));
/* replacement string register */
@@ -402,7 +407,7 @@ main(int argc, char **argv)
teco_initialize_environment();
teco_qreg_table_t local_qregs;
- teco_qreg_table_init(&local_qregs, TRUE);
+ teco_qreg_table_init_locals(&local_qregs, TRUE);
if (!teco_ring_edit_by_name(NULL, &error)) {
g_fprintf(stderr, "Error editing unnamed file: %s\n",
diff --git a/src/parser.c b/src/parser.c
index 4ee6a90..9477b9a 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -176,7 +176,7 @@ teco_execute_macro(const gchar *macro, gsize macro_len,
teco_qreg_table_t macro_locals;
if (!qreg_table_locals)
- teco_qreg_table_init(&macro_locals, FALSE);
+ teco_qreg_table_init_locals(&macro_locals, FALSE);
guint parent_brace_level = teco_brace_level;
@@ -670,7 +670,7 @@ teco_state_stringbuilding_ctle_num_input(teco_machine_stringbuilding_t *ctx, gun
* NOTE: Numbers can always be safely formatted as null-terminated strings.
*/
gchar buffer[TECO_EXPRESSIONS_FORMAT_LEN];
- const gchar *num = teco_expressions_format(buffer, value);
+ const gchar *num = teco_expressions_format(buffer, value, ctx->qreg_table_locals->radix);
teco_machine_stringbuilding_append(ctx, num, strlen(num));
return &teco_state_stringbuilding_start;
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index d593af8..89618da 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -654,7 +654,7 @@ teco_state_macro_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
return NULL;
} else {
g_auto(teco_qreg_table_t) table;
- teco_qreg_table_init(&table, FALSE);
+ teco_qreg_table_init_locals(&table, FALSE);
if (!teco_qreg_execute(qreg, &table, error))
return NULL;
@@ -711,7 +711,8 @@ teco_state_macrofile_done(teco_machine_main_t *ctx, const teco_string_t *str, GE
return NULL;
} else {
g_auto(teco_qreg_table_t) table;
- teco_qreg_table_init(&table, FALSE);
+ teco_qreg_table_init_locals(&table, FALSE);
+
if (!teco_execute_file(filename, &table, error))
return NULL;
}
diff --git a/src/qreg.c b/src/qreg.c
index 487a725..2c5d4a5 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -893,6 +893,7 @@ teco_qreg_clipboard_new(const gchar *name)
void
teco_qreg_table_init(teco_qreg_table_t *table, gboolean must_undo)
{
+ memset(table, 0, sizeof(*table));
rb3_reset_tree(&table->tree);
table->must_undo = must_undo;
@@ -903,6 +904,20 @@ teco_qreg_table_init(teco_qreg_table_t *table, gboolean must_undo)
teco_qreg_table_insert(table, teco_qreg_plain_new(&q, sizeof(q)));
}
+/** @memberof teco_qreg_table_t */
+void
+teco_qreg_table_init_locals(teco_qreg_table_t *table, gboolean must_undo)
+{
+ teco_qreg_table_init(table, must_undo);
+
+ /* search mode ("^X") */
+ teco_qreg_table_insert(table, teco_qreg_plain_new("\x18", 1));
+ /* numeric radix ("^R") */
+ table->radix = teco_qreg_plain_new("\x12", 1);
+ table->radix->vtable->set_integer(table->radix, 10, NULL);
+ teco_qreg_table_insert(table, table->radix);
+}
+
static inline void
teco_qreg_table_remove(teco_qreg_t *reg)
{
@@ -1208,7 +1223,7 @@ teco_ed_hook(teco_ed_hook_t type, GError **error)
* since it runs all destructors.
*/
g_auto(teco_qreg_table_t) locals;
- teco_qreg_table_init(&locals, FALSE);
+ teco_qreg_table_init_locals(&locals, FALSE);
teco_qreg_t *qreg = teco_qreg_table_find(&teco_qreg_table_globals, "ED", 2);
if (!qreg) {
@@ -1297,6 +1312,7 @@ struct teco_machine_qregspec_t {
*/
TECO_DECLARE_STATE(teco_state_qregspec_start);
TECO_DECLARE_STATE(teco_state_qregspec_start_global);
+TECO_DECLARE_STATE(teco_state_qregspec_caret);
TECO_DECLARE_STATE(teco_state_qregspec_firstchar);
TECO_DECLARE_STATE(teco_state_qregspec_secondchar);
TECO_DECLARE_STATE(teco_state_qregspec_string);
@@ -1364,10 +1380,10 @@ TECO_DEFINE_STATE(teco_state_qregspec_start,
static teco_state_t *
teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error)
{
- /*
- * FIXME: Disallow space characters?
- */
switch (chr) {
+ case '^':
+ return &teco_state_qregspec_caret;
+
case '#':
return &teco_state_qregspec_firstchar;
@@ -1397,6 +1413,25 @@ TECO_DEFINE_STATE(teco_state_qregspec_start_global,
);
static teco_state_t *
+teco_state_qregspec_caret_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error)
+{
+ chr = teco_ascii_toupper(chr);
+ if (chr < '@' || chr > '_') {
+ teco_error_syntax_set(error, chr);
+ return NULL;
+ }
+
+ if (!ctx->parse_only) {
+ if (ctx->parent.must_undo)
+ undo__teco_string_truncate(&ctx->name, ctx->name.len);
+ teco_string_append_wc(&ctx->name, TECO_CTL_KEY(chr));
+ }
+ return teco_state_qregspec_done(ctx, error);
+}
+
+TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_qregspec_caret);
+
+static teco_state_t *
teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error)
{
/*
diff --git a/src/qreg.h b/src/qreg.h
index e9a9b1b..4a7c15c 100644
--- a/src/qreg.h
+++ b/src/qreg.h
@@ -144,9 +144,16 @@ struct teco_qreg_table_t {
* b) The top-level local register table.
*/
gboolean must_undo;
+
+ /**
+ * The radix register in this local Q-Register table or NULL.
+ * This is an optimization to avoid frequent table lookups.
+ */
+ teco_qreg_t *radix;
};
void teco_qreg_table_init(teco_qreg_table_t *table, gboolean must_undo);
+void teco_qreg_table_init_locals(teco_qreg_table_t *table, gboolean must_undo);
/** @memberof teco_qreg_table_t */
static inline teco_qreg_t *
diff --git a/src/search.c b/src/search.c
index ec62d02..2059da3 100644
--- a/src/search.c
+++ b/src/search.c
@@ -52,8 +52,6 @@ TECO_DEFINE_UNDO_OBJECT_OWN(parameters, teco_search_parameters_t, /* don't delet
*/
static teco_search_parameters_t teco_search_parameters;
-static teco_bool_t teco_search_mode = TECO_FAILURE; /* case-insensitive */
-
/*$ ^X search-mode
* mode^X -- Set or get search mode flag
* -^X
@@ -65,17 +63,29 @@ static teco_bool_t teco_search_mode = TECO_FAILURE; /* case-insensitive */
* searches.
* "-^X" is equivalent to "-1^X" and also enables case-sensitive searches.
* Searches are case-insensitive by default.
+ *
+ * An alternative way to access the search mode is via the "^X" local Q-Register.
+ * Consequently, the search mode is local to the current macro invocation frame,
+ * unless the macro call was colon-modified.
*/
void
teco_state_control_search_mode(teco_machine_main_t *ctx, GError **error)
{
if (!teco_expressions_eval(FALSE, error))
return;
+
+ teco_qreg_t *reg = teco_qreg_table_find(ctx->qreg_table_locals, "\x18", 1); /* ^X */
+ g_assert(reg != NULL);
+ teco_bool_t search_mode;
+
if (!teco_expressions_args() && teco_num_sign > 0) {
- teco_expressions_push(teco_search_mode);
+ if (!reg->vtable->get_integer(reg, &search_mode, error))
+ return;
+ teco_expressions_push(search_mode);
} else {
- teco_undo_int(teco_search_mode);
- if (!teco_expressions_pop_num_calc(&teco_search_mode, teco_num_sign, error))
+ if (!teco_expressions_pop_num_calc(&search_mode, teco_num_sign, error) ||
+ !reg->vtable->undo_set_integer(reg, error) ||
+ !reg->vtable->set_integer(reg, search_mode, error))
return;
}
}
@@ -629,7 +639,12 @@ teco_state_search_process(teco_machine_main_t *ctx, const teco_string_t *str, gs
/* FIXME: Should G_REGEX_OPTIMIZE be added under certain circumstances? */
GRegexCompileFlags flags = G_REGEX_MULTILINE | G_REGEX_DOTALL;
- if (teco_is_failure(teco_search_mode))
+ teco_qreg_t *reg = teco_qreg_table_find(ctx->qreg_table_locals, "\x18", 1); /* ^X */
+ g_assert(reg != NULL);
+ teco_bool_t search_mode;
+ if (!reg->vtable->get_integer(reg, &search_mode, error))
+ return FALSE;
+ if (teco_is_failure(search_mode))
flags |= G_REGEX_CASELESS;
/* this is set in teco_state_search_initial() */