aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
m---------contrib/terex0
-rw-r--r--lib/lexer.tes2
-rw-r--r--src/cmdline.c10
-rw-r--r--src/core-commands.c98
-rw-r--r--src/core-commands.h3
-rw-r--r--src/doc.c13
-rw-r--r--src/doc.h24
-rw-r--r--src/glob.c24
-rw-r--r--src/help.c13
-rw-r--r--src/interface.h64
-rw-r--r--src/move-commands.c72
-rw-r--r--src/parser.c2
-rw-r--r--src/qreg-commands.c23
-rw-r--r--src/qreg.c47
-rw-r--r--src/qreg.h6
-rw-r--r--src/ring.c13
-rw-r--r--src/ring.h26
-rw-r--r--src/search.c53
-rw-r--r--src/spawn.c13
-rw-r--r--src/stdio-commands.c2
-rw-r--r--src/view.c113
-rw-r--r--src/view.h7
-rw-r--r--tests/testsuite.at26
23 files changed, 458 insertions, 196 deletions
diff --git a/contrib/terex b/contrib/terex
-Subproject b00e966f85221c3702a1f3f90e9494eb480876d
+Subproject 438128e7370d0a08f363bace4f690bd48f3804c
diff --git a/lib/lexer.tes b/lib/lexer.tes
index af6793a..f7c1ae4 100644
--- a/lib/lexer.tes
+++ b/lib/lexer.tes
@@ -26,7 +26,7 @@
!* Automatically mung all the lexers and add them to "lexer.auto" *!
[*
EQ.[lexers]
- [_ 1ENQ[$SCITECOPATH]/lexers/*.tes ]_ J
+ [_ 1ENN[$SCITECOPATH]/lexers/*.tes ]_ J
<:L;R
0X.[filename] 4R .U.p <-A-^^/"= 1; ':R;> .,Q.pX.[name]
EIQ.[filename]
diff --git a/src/cmdline.c b/src/cmdline.c
index b944b5e..8b2aebd 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -476,12 +476,10 @@ teco_cmdline_keymacro(const gchar *name, gssize name_len, GError **error)
static void
teco_cmdline_rubout(void)
{
- gsize effective_len = teco_cmdline_ssm(SCI_GETCURRENTPOS, 0, 0);
- gssize p = teco_view_glyphs2bytes_relative(teco_cmdline.view, effective_len, -1);
- if (p >= 0) {
- teco_cmdline_ssm(SCI_GOTOPOS, p, 0);
- teco_undo_pop(p);
- }
+ sptr_t effective_len = teco_cmdline_ssm(SCI_GETCURRENTPOS, 0, 0);
+ sptr_t p = teco_cmdline_ssm(SCI_POSITIONRELATIVE, effective_len, -1);
+ teco_cmdline_ssm(SCI_GOTOPOS, p, 0);
+ teco_undo_pop(p);
}
/**
diff --git a/src/core-commands.c b/src/core-commands.c
index 81d5869..9c70825 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -72,7 +72,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 +100,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 +212,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 +229,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 +247,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 +279,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 +287,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 +576,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
@@ -617,8 +636,7 @@ teco_state_start_get(teco_machine_main_t *ctx, GError **error)
if (!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
@@ -1345,8 +1363,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 +1375,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 +1406,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 +1459,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 +2681,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 +2729,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 +2773,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
@@ -2928,8 +2943,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 +2956,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 +3002,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 +3032,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 +3079,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);
diff --git a/src/core-commands.h b/src/core-commands.h
index 254c4a7..6a31b92 100644
--- a/src/core-commands.h
+++ b/src/core-commands.h
@@ -29,7 +29,8 @@ teco_is_noop(gunichar c)
return c == ' ' || c == '\f' || c == '\r' || c == '\n' || c == '\v';
}
-gboolean teco_get_range_args(const gchar *cmd, gsize *from_ret, gsize *len_ret, GError **error);
+gboolean 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);
/* in cmdline.c */
gboolean teco_state_command_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx,
diff --git a/src/doc.c b/src/doc.c
index 9bc9dc8..40217f4 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -77,7 +77,7 @@ teco_doc_edit(teco_doc_t *ctx, guint default_cp)
(sptr_t)teco_doc_get_scintilla(ctx));
teco_view_ssm(teco_qreg_view, SCI_SETFIRSTVISIBLELINE, ctx->first_line, 0);
teco_view_ssm(teco_qreg_view, SCI_SETXOFFSET, ctx->xoffset, 0);
- teco_view_ssm(teco_qreg_view, SCI_SETSEL, ctx->anchor, (sptr_t)ctx->dot);
+ teco_view_ssm(teco_qreg_view, SCI_SETSEL, ctx->anchor, (sptr_t)ctx->pos);
/*
* NOTE: Thanks to a custom Scintilla patch, representations
@@ -124,7 +124,7 @@ teco_doc_undo_edit(teco_doc_t *ctx)
*/
//undo__teco_view_set_representations(teco_qreg_view);
- undo__teco_view_ssm(teco_qreg_view, SCI_SETSEL, ctx->anchor, (sptr_t)ctx->dot);
+ undo__teco_view_ssm(teco_qreg_view, SCI_SETSEL, ctx->anchor, (sptr_t)ctx->pos);
undo__teco_view_ssm(teco_qreg_view, SCI_SETXOFFSET, ctx->xoffset, 0);
undo__teco_view_ssm(teco_qreg_view, SCI_SETFIRSTVISIBLELINE, ctx->first_line, 0);
undo__teco_view_ssm(teco_qreg_view, SCI_SETDOCPOINTER, 0,
@@ -222,9 +222,11 @@ void
teco_doc_update_from_view(teco_doc_t *ctx, teco_view_t *from)
{
ctx->anchor = teco_view_ssm(from, SCI_GETANCHOR, 0, 0);
- ctx->dot = teco_view_ssm(from, SCI_GETCURRENTPOS, 0, 0);
+ ctx->pos = teco_view_ssm(from, SCI_GETCURRENTPOS, 0, 0);
ctx->first_line = teco_view_ssm(from, SCI_GETFIRSTVISIBLELINE, 0, 0);
ctx->xoffset = teco_view_ssm(from, SCI_GETXOFFSET, 0, 0);
+
+ ctx->dot = teco_view_bytes2glyphs_rel(from, 0, 0, ctx->pos);
}
/** @memberof teco_doc_t */
@@ -232,9 +234,11 @@ void
teco_doc_update_from_doc(teco_doc_t *ctx, const teco_doc_t *from)
{
ctx->anchor = from->anchor;
- ctx->dot = from->dot;
+ ctx->pos = from->pos;
ctx->first_line = from->first_line;
ctx->xoffset = from->xoffset;
+
+ ctx->dot = from->dot;
}
/**
@@ -252,7 +256,6 @@ teco_doc_exchange(teco_doc_t *ctx, teco_doc_t *other)
memcpy(other, &temp, sizeof(*other));
}
-/** @memberof teco_doc_t */
void
teco_doc_clear(teco_doc_t *ctx)
{
diff --git a/src/doc.h b/src/doc.h
index 3218a70..c4e0f3a 100644
--- a/src/doc.h
+++ b/src/doc.h
@@ -51,10 +51,17 @@ typedef struct {
/*
* The so called "parameters".
+ * They are all in bytes.
* Updated/restored only when required
*/
- gint anchor, dot;
- gint first_line, xoffset;
+ gsize anchor, pos;
+ guint first_line, xoffset;
+
+ /**
+ * Dot in glyphs.
+ * This field is always kept up to date.
+ */
+ teco_int_t dot;
} teco_doc_t;
/** @memberof teco_doc_t */
@@ -85,8 +92,9 @@ void teco_doc_update_from_doc(teco_doc_t *ctx, const teco_doc_t *from);
static inline void
teco_doc_reset(teco_doc_t *ctx)
{
- ctx->anchor = ctx->dot = 0;
+ ctx->anchor = ctx->pos = 0;
ctx->first_line = ctx->xoffset = 0;
+ ctx->dot = 0;
}
/** @memberof teco_doc_t */
@@ -98,10 +106,12 @@ teco_doc_undo_reset(teco_doc_t *ctx)
* and called with teco_undo_call() if we really
* wanted to save more memory.
*/
- teco_undo_gint(ctx->anchor);
- teco_undo_gint(ctx->dot);
- teco_undo_gint(ctx->first_line);
- teco_undo_gint(ctx->xoffset);
+ teco_undo_gsize(ctx->anchor);
+ teco_undo_gsize(ctx->pos);
+ teco_undo_guint(ctx->first_line);
+ teco_undo_guint(ctx->xoffset);
+
+ teco_undo_int(ctx->dot);
}
void teco_doc_exchange(teco_doc_t *ctx, teco_doc_t *other);
diff --git a/src/glob.c b/src/glob.c
index 0917e5c..cb571c4 100644
--- a/src/glob.c
+++ b/src/glob.c
@@ -38,6 +38,7 @@
#include "expressions.h"
#include "qreg.h"
#include "ring.h"
+#include "view.h"
#include "error.h"
#include "undo.h"
#include "glob.h"
@@ -527,21 +528,24 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
gint rc = tere_exec(&pattern, (chr *)filename, strlen(filename), NULL, 0, NULL, 0);
if (rc == REG_OKAY && (teco_test_mode == 0 || g_file_test(filename, file_flags))) {
if (!colon_modified) {
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
-
/*
* FIXME: Filenames may contain linefeeds.
* But if we add them null-terminated, they will be relatively hard to parse.
*/
gsize len = strlen(filename);
filename[len] = '\n';
+
+ sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot();
+
teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_interface_ssm(SCI_ADDTEXT, len+1, (sptr_t)filename);
teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
- teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(pos);
- teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs(pos + len + 1);
+ teco_int_t to = teco_interface_bytes2glyphs_rel(teco_ranges[0].from, pos, len + 1);
+ teco_undo_int(teco_ranges[0].to) = to;
teco_undo_guint(teco_ranges_count) = 1;
+ teco_current_doc_set_dot(to);
}
matching = TRUE;
@@ -565,14 +569,15 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
globber = teco_globber_new(pattern_str.data, file_flags);
sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
- teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(pos);
+ gsize total_len = 0;
+ teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot();
teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
gchar *globbed_filename;
while ((globbed_filename = teco_globber_next(globber))) {
gsize len = strlen(globbed_filename);
- pos += len+1;
+ total_len += len+1;
/*
* FIXME: Filenames may contain linefeeds.
@@ -587,8 +592,10 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
- teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs(pos);
+ teco_int_t to = teco_interface_bytes2glyphs_rel(teco_ranges[0].from, pos, total_len);
+ teco_undo_int(teco_ranges[0].to) = to;
teco_undo_guint(teco_ranges_count) = 1;
+ teco_current_doc_set_dot(to);
}
if (colon_modified) {
@@ -600,8 +607,7 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, teco_string_t str, GErro
undo__teco_interface_ssm(SCI_UNDO, 0, 0);
}
- if (!glob_reg->vtable->undo_set_integer(glob_reg, error) ||
- !glob_reg->vtable->set_integer(glob_reg, teco_bool(matching), error))
+ if (!glob_reg->vtable->set_integer(glob_reg, teco_bool(matching), error))
return NULL;
return &teco_state_start;
diff --git a/src/help.c b/src/help.c
index 03cc595..c64538e 100644
--- a/src/help.c
+++ b/src/help.c
@@ -38,7 +38,7 @@
#include "rb3str.h"
#include "help.h"
-static void teco_help_set(const gchar *topic_name, const gchar *filename, teco_int_t pos);
+static void teco_help_set(const gchar *topic_name, const gchar *filename, gsize pos);
static GStringChunk *teco_help_chunk = NULL;
@@ -46,13 +46,14 @@ static GStringChunk *teco_help_chunk = NULL;
typedef struct {
teco_rb3str_head_t head;
- teco_int_t pos;
+ /** position of topic in filename (in bytes) */
+ gsize pos;
gchar filename[];
} teco_help_topic_t;
/** @static @memberof teco_help_topic_t */
static teco_help_topic_t *
-teco_help_topic_new(const gchar *topic_name, const gchar *filename, teco_int_t pos)
+teco_help_topic_new(const gchar *topic_name, const gchar *filename, gsize pos)
{
/*
* Topics are inserted only once into the RB tree, so we can store
@@ -157,7 +158,7 @@ teco_help_init(GError **error)
do {
gchar *endptr;
- teco_int_t pos = strtoul(topic, &endptr, 10);
+ gsize pos = strtoul(topic, &endptr, 10);
/*
* This also breaks at the last line of the
@@ -196,7 +197,7 @@ teco_help_find(const gchar *topic_name)
}
static void
-teco_help_set(const gchar *topic_name, const gchar *filename, teco_int_t pos)
+teco_help_set(const gchar *topic_name, const gchar *filename, gsize pos)
{
teco_help_topic_t *topic;
teco_help_topic_t *existing = teco_help_find(topic_name);
@@ -298,6 +299,8 @@ teco_state_help_done(teco_machine_main_t *ctx, teco_string_t str, GError **error
!teco_ring_edit(topic->filename, error))
return NULL;
+ teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(topic->pos));
+
/*
* Make sure the topic is visible.
* We do need undo tokens for this (even though
diff --git a/src/interface.h b/src/interface.h
index a7968d1..9c3d31e 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -211,21 +211,73 @@ teco_interface_get_codepage(void)
}
static inline gssize
-teco_interface_glyphs2bytes(teco_int_t pos)
+teco_interface_glyphs2bytes_rel(teco_int_t pos_glyphs, gsize pos, teco_int_t n)
{
- return teco_view_glyphs2bytes(teco_interface_current_view, pos);
+ return teco_view_glyphs2bytes_rel(teco_interface_current_view,
+ pos_glyphs, pos, n);
}
static inline teco_int_t
-teco_interface_bytes2glyphs(gsize pos)
+teco_interface_bytes2glyphs_rel(teco_int_t pos_glyphs, gsize pos, gssize n)
{
- return teco_view_bytes2glyphs(teco_interface_current_view, pos);
+ return teco_view_bytes2glyphs_rel(teco_interface_current_view,
+ pos_glyphs, pos, n);
}
+/**
+ * Convert absolute glyph position to bytes.
+ *
+ * This allows for scanning around dot and should be used if
+ * pos can be expected to be close to dot.
+ * Dot in glyphs as set by teco_current_doc_set_dot()
+ * \b must be up to date for this to work.
+ */
+static inline gssize
+teco_interface_glyphs2bytes_absdot(teco_int_t pos)
+{
+ teco_int_t dot = teco_current_doc_get_dot();
+ gsize curpos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ return teco_interface_glyphs2bytes_rel(dot, curpos, pos-dot);
+}
+
+/**
+ * Convert absolute byte position to glyphs.
+ *
+ * @see teco_interface_glyphs2bytes_absdot
+ */
+static inline teco_int_t
+teco_interface_bytes2glyphs_absdot(gsize pos)
+{
+ teco_int_t dot = teco_current_doc_get_dot();
+ gsize curpos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ return teco_interface_bytes2glyphs_rel(dot, curpos, pos-curpos);
+}
+
+/**
+ * Convert relative glyph position to bytes.
+ *
+ * Dot in glyphs as set by teco_current_doc_set_dot()
+ * \b must be up to date for this to work.
+ */
static inline gssize
-teco_interface_glyphs2bytes_relative(gsize pos, teco_int_t n)
+teco_interface_glyphs2bytes_reldot(teco_int_t n)
+{
+ teco_int_t dot = teco_current_doc_get_dot();
+ gsize curpos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ return teco_interface_glyphs2bytes_rel(dot, curpos, n);
+}
+
+/**
+ * Convert relative byte position to glyphs.
+ *
+ * @see teco_interface_glyphs2bytes_reldot
+ */
+static inline teco_int_t
+teco_interface_bytes2glyphs_reldot(gssize n)
{
- return teco_view_glyphs2bytes_relative(teco_interface_current_view, pos, n);
+ teco_int_t dot = teco_current_doc_get_dot();
+ gsize curpos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ return teco_interface_bytes2glyphs_rel(dot, curpos, n);
}
static inline teco_int_t
diff --git a/src/move-commands.c b/src/move-commands.c
index 45afc4e..9ef893e 100644
--- a/src/move-commands.c
+++ b/src/move-commands.c
@@ -58,12 +58,13 @@ teco_state_start_jump(teco_machine_main_t *ctx, GError **error)
if (!teco_expressions_pop_num_calc(&v, 0, error))
return;
- gssize pos = teco_interface_glyphs2bytes(v);
- if (pos >= 0) {
+ gssize next_pos = teco_interface_glyphs2bytes_absdot(v);
+ if (next_pos >= 0) {
if (teco_current_doc_must_undo())
undo__teco_interface_ssm(SCI_GOTOPOS,
teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), 0);
- teco_interface_ssm(SCI_GOTOPOS, pos, 0);
+ teco_interface_ssm(SCI_GOTOPOS, next_pos, 0);
+ teco_current_doc_set_dot(v);
if (teco_machine_main_eval_colon(ctx) > 0)
teco_expressions_push(TECO_SUCCESS);
@@ -78,14 +79,15 @@ teco_state_start_jump(teco_machine_main_t *ctx, GError **error)
static teco_bool_t
teco_move_chars(teco_int_t n)
{
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
- gssize next_pos = teco_interface_glyphs2bytes_relative(pos, n);
+ gssize next_pos = teco_interface_glyphs2bytes_reldot(n);
if (next_pos < 0)
return TECO_FAILURE;
- teco_interface_ssm(SCI_GOTOPOS, next_pos, 0);
if (teco_current_doc_must_undo())
- undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
+ undo__teco_interface_ssm(SCI_GOTOPOS, teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), 0);
+
+ teco_interface_ssm(SCI_GOTOPOS, next_pos, 0);
+ teco_current_doc_set_dot(teco_current_doc_get_dot() + n);
return TECO_SUCCESS;
}
@@ -151,7 +153,15 @@ teco_move_lines(teco_int_t n)
if (!teco_validate_line(line))
return TECO_FAILURE;
- teco_interface_ssm(SCI_GOTOLINE, line, 0);
+ sptr_t next_pos = teco_interface_ssm(SCI_POSITIONFROMLINE, line, 0);
+ /*
+ * FIXME: Perhaps it would be more efficient to fall back to the
+ * line index cache via teco_view_bytes2glyphs_unicode() since next_pos
+ * is guaranteed to fall on line starts.
+ */
+ teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(next_pos));
+ teco_interface_ssm(SCI_GOTOPOS, next_pos, 0);
+
if (teco_current_doc_must_undo())
undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
@@ -388,6 +398,8 @@ teco_state_start_words(teco_machine_main_t *ctx, const gchar *cmd, gint factor,
if (rc) {
if (teco_current_doc_must_undo())
undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
+
+ teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(word_pos));
teco_interface_ssm(SCI_GOTOPOS, word_pos, 0);
}
@@ -457,6 +469,9 @@ teco_state_start_delete_words(teco_machine_main_t *ctx, const gchar *cmd, gint f
if (rc && start_pos != end_pos) {
g_assert(start_pos < end_pos);
+ if (start_pos < pos)
+ teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(start_pos));
+
teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_interface_ssm(SCI_DELETERANGE, start_pos, end_pos-start_pos);
teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
@@ -487,8 +502,10 @@ teco_state_start_kill(teco_machine_main_t *ctx, const gchar *cmd, gboolean by_li
if (!teco_expressions_eval(FALSE, error))
return FALSE;
+ sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+
if (teco_expressions_args() <= 1) {
- from = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ from = pos;
if (by_lines) {
teco_int_t line;
if (!teco_expressions_pop_num_calc(&line, teco_num_sign, error))
@@ -496,13 +513,24 @@ teco_state_start_kill(teco_machine_main_t *ctx, const gchar *cmd, gboolean by_li
line += teco_interface_ssm(SCI_LINEFROMPOSITION, from, 0);
len = teco_interface_ssm(SCI_POSITIONFROMLINE, line, 0) - from;
rc = teco_bool(teco_validate_line(line));
+
+ /*
+ * FIXME: Perhaps it would be more efficient to fall back to the
+ * line index cache via teco_view_bytes2glyphs_unicode() since from+len
+ * is guaranteed to fall on line starts.
+ */
+ if (teco_is_success(rc) && len < 0)
+ teco_current_doc_set_dot(teco_interface_bytes2glyphs_reldot(len));
} else {
teco_int_t len_glyphs;
if (!teco_expressions_pop_num_calc(&len_glyphs, teco_num_sign, error))
return FALSE;
- gssize to = teco_interface_glyphs2bytes_relative(from, len_glyphs);
+ gssize to = teco_interface_glyphs2bytes_reldot(len_glyphs);
rc = teco_bool(to >= 0);
len = to-from;
+
+ if (teco_is_success(rc) && len_glyphs < 0)
+ teco_current_doc_set_dot(teco_current_doc_get_dot() + len_glyphs);
}
if (len < 0) {
len *= -1;
@@ -510,11 +538,18 @@ teco_state_start_kill(teco_machine_main_t *ctx, const gchar *cmd, gboolean by_li
}
} else {
teco_int_t to_glyphs = teco_expressions_pop_num(0);
- gssize to = teco_interface_glyphs2bytes(to_glyphs);
+ gssize to = teco_interface_glyphs2bytes_absdot(to_glyphs);
teco_int_t from_glyphs = teco_expressions_pop_num(0);
- from = teco_interface_glyphs2bytes(from_glyphs);
+ from = teco_interface_glyphs2bytes_absdot(from_glyphs);
len = to - from;
rc = teco_bool(len >= 0 && from >= 0 && to >= 0);
+
+ if (teco_is_success(rc)) {
+ if (to < pos)
+ teco_current_doc_set_dot(teco_current_doc_get_dot() - (to_glyphs-from_glyphs));
+ else if (from < pos)
+ teco_current_doc_set_dot(from_glyphs);
+ }
}
if (teco_machine_main_eval_colon(ctx) > 0) {
@@ -528,7 +563,6 @@ teco_state_start_kill(teco_machine_main_t *ctx, const gchar *cmd, gboolean by_li
return TRUE;
if (teco_current_doc_must_undo()) {
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
undo__teco_interface_ssm(SCI_UNDO, 0, 0);
}
@@ -629,7 +663,11 @@ teco_state_control_lines2glyphs(teco_machine_main_t *ctx, GError **error)
if (!teco_expressions_args()) {
pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
} else {
- pos = teco_interface_glyphs2bytes(teco_expressions_pop_num(0));
+ /*
+ * FIXME: Could be optimized by directly calling
+ * SCI_LINEFROMINDEXPOSITION.
+ */
+ pos = teco_interface_glyphs2bytes_absdot(teco_expressions_pop_num(0));
if (pos < 0) {
teco_error_range_set(error, "^Q");
return;
@@ -652,6 +690,10 @@ teco_state_control_lines2glyphs(teco_machine_main_t *ctx, GError **error)
}
sptr_t line_pos = teco_interface_ssm(SCI_POSITIONFROMLINE, line, 0);
- teco_expressions_push(teco_interface_bytes2glyphs(line_pos) - teco_interface_bytes2glyphs(pos));
+ /*
+ * FIXME: Could be optimized with SCI_INDEXPOSITIONFROMLINE.
+ */
+ teco_expressions_push(teco_interface_bytes2glyphs_absdot(line_pos) -
+ teco_current_doc_get_dot());
}
}
diff --git a/src/parser.c b/src/parser.c
index 747249d..c84881b 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -123,7 +123,7 @@ teco_machine_main_step(teco_machine_main_t *ctx, const gchar *macro, gsize stop_
gunichar chr = g_utf8_get_char(macro+ctx->macro_pc);
#ifdef DEBUG
- g_printf("EXEC(%d): input='%C' (U+%04" G_GINT32_MODIFIER "X), state=%p, mode=%d\n",
+ g_printf("EXEC(%zu): input='%C' (U+%04" G_GINT32_MODIFIER "X), state=%p, mode=%d\n",
ctx->macro_pc, chr, chr, ctx->parent.current, ctx->flags.mode);
#endif
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index 4ede403..a6390a1 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -572,9 +572,11 @@ teco_state_getqregstring_got_register(teco_machine_main_t *ctx, teco_qreg_t *qre
undo__teco_interface_ssm(SCI_UNDO, 0, 0);
}
- teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(pos);
- teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs(pos + str.len);
+ teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot();
+ teco_int_t to = teco_interface_bytes2glyphs_rel(teco_ranges[0].from, pos, str.len);
+ teco_undo_int(teco_ranges[0].to) = to;
teco_undo_guint(teco_ranges_count) = 1;
+ teco_current_doc_set_dot(to);
return &teco_state_start;
}
@@ -609,7 +611,6 @@ teco_state_setqreginteger_got_register(teco_machine_main_t *ctx, teco_qreg_t *qr
if (teco_expressions_args() || teco_num_sign < 0) {
teco_int_t v;
if (!teco_expressions_pop_num_calc(&v, teco_num_sign, error) ||
- !qreg->vtable->undo_set_integer(qreg, error) ||
!qreg->vtable->set_integer(qreg, v, error))
return NULL;
@@ -657,8 +658,7 @@ teco_state_increaseqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg
teco_int_t value, add;
- if (!qreg->vtable->undo_set_integer(qreg, error) ||
- !qreg->vtable->get_integer(qreg, &value, error) ||
+ if (!qreg->vtable->get_integer(qreg, &value, error) ||
!teco_expressions_pop_num_calc(&add, teco_num_sign, error) ||
!qreg->vtable->set_integer(qreg, value += add, error))
return NULL;
@@ -798,9 +798,10 @@ teco_state_copytoqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
+ teco_int_t from_glyphs, len_glyphs;
gsize from, len;
- if (!teco_get_range_args("X", &from, &len, error))
+ if (!teco_get_range_args("X", &from_glyphs, &from, &len_glyphs, &len, error))
return NULL;
/*
@@ -829,11 +830,12 @@ teco_state_copytoqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
if (!modifier_at || len == 0)
return &teco_state_start;
+ sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+
/*
* If @-modified, cut into the register
*/
if (teco_current_doc_must_undo()) {
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
undo__teco_interface_ssm(SCI_GOTOPOS, pos, 0);
undo__teco_interface_ssm(SCI_UNDO, 0, 0);
}
@@ -846,6 +848,13 @@ teco_state_copytoqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
teco_ring_dirtify();
+ if (from+len < pos)
+ /* dot after deleted range */
+ teco_current_doc_set_dot(teco_current_doc_get_dot() - len_glyphs);
+ else if (from <= pos)
+ /* dot falls on deleted range */
+ teco_current_doc_set_dot(from_glyphs);
+
return &teco_state_start;
}
diff --git a/src/qreg.c b/src/qreg.c
index 8ef82c0..559373c 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -138,15 +138,9 @@ teco_qreg_set_eol_mode(teco_qreg_t *qreg, gint mode)
static gboolean
teco_qreg_plain_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error)
{
- qreg->integer = value;
- return TRUE;
-}
-
-static gboolean
-teco_qreg_plain_undo_set_integer(teco_qreg_t *qreg, GError **error)
-{
if (qreg->must_undo) // FIXME
teco_undo_int(qreg->integer);
+ qreg->integer = value;
return TRUE;
}
@@ -237,8 +231,10 @@ teco_qreg_plain_get_character(teco_qreg_t *qreg, teco_int_t position,
teco_doc_edit(&qreg->string, teco_default_codepage());
+ sptr_t curpos = teco_view_ssm(teco_qreg_view, SCI_GETCURRENTPOS, 0, 0);
sptr_t len = teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0);
- gssize off = teco_view_glyphs2bytes(teco_qreg_view, position);
+ gssize off = teco_view_glyphs2bytes_rel(teco_qreg_view, qreg->string.dot, curpos,
+ position - qreg->string.dot);
*chr = off >= 0 && off != len ? teco_view_get_character(teco_qreg_view, off, len) : -1;
@@ -256,8 +252,10 @@ teco_qreg_plain_get_length(teco_qreg_t *qreg, GError **error)
teco_doc_edit(&qreg->string, teco_default_codepage());
+ sptr_t curpos = teco_view_ssm(teco_qreg_view, SCI_GETCURRENTPOS, 0, 0);
sptr_t len = teco_view_ssm(teco_qreg_view, SCI_GETLENGTH, 0, 0);
- teco_int_t ret = teco_view_bytes2glyphs(teco_qreg_view, len);
+ teco_int_t ret = teco_view_bytes2glyphs_rel(teco_qreg_view, qreg->string.dot,
+ curpos, len - curpos);
if (teco_qreg_current)
teco_doc_edit(&teco_qreg_current->string, 0);
@@ -366,7 +364,6 @@ teco_qreg_plain_save(teco_qreg_t *qreg, const gchar *filename, GError **error)
*/
#define TECO_INIT_QREG(...) { \
.set_integer = teco_qreg_plain_set_integer, \
- .undo_set_integer = teco_qreg_plain_undo_set_integer, \
.get_integer = teco_qreg_plain_get_integer, \
.set_string = teco_qreg_plain_set_string, \
.undo_set_string = teco_qreg_plain_undo_set_string, \
@@ -396,23 +393,20 @@ teco_qreg_plain_new(const gchar *name, gsize len)
static gboolean
teco_qreg_dot_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error)
{
- gssize pos = teco_interface_glyphs2bytes(value);
+ gssize pos = teco_interface_glyphs2bytes_absdot(value);
if (pos < 0) {
g_set_error_literal(error, TECO_ERROR, TECO_ERROR_MOVE,
"Attempt to move pointer off page when setting Q-Register \":\"");
return FALSE;
}
- teco_interface_ssm(SCI_GOTOPOS, pos, 0);
- return TRUE;
-}
-
-static gboolean
-teco_qreg_dot_undo_set_integer(teco_qreg_t *qreg, GError **error)
-{
if (teco_current_doc_must_undo())
undo__teco_interface_ssm(SCI_GOTOPOS,
teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), 0);
+
+ teco_interface_ssm(SCI_GOTOPOS, pos, 0);
+ teco_current_doc_set_dot(value);
+
return TRUE;
}
@@ -420,8 +414,7 @@ teco_qreg_dot_undo_set_integer(teco_qreg_t *qreg, GError **error)
static gboolean
teco_qreg_dot_get_integer(teco_qreg_t *qreg, teco_int_t *ret, GError **error)
{
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
- *ret = teco_interface_bytes2glyphs(pos);
+ *ret = teco_current_doc_get_dot();
return TRUE;
}
@@ -431,7 +424,6 @@ teco_qreg_dot_new(void)
{
static teco_qreg_vtable_t vtable = TECO_INIT_QREG(
.set_integer = teco_qreg_dot_set_integer,
- .undo_set_integer = teco_qreg_dot_undo_set_integer,
.get_integer = teco_qreg_dot_get_integer
);
@@ -631,13 +623,8 @@ teco_qreg_external_save(teco_qreg_t *qreg, const gchar *filename, GError **error
static gboolean
teco_qreg_bufferinfo_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error)
{
- return teco_ring_edit(value, error);
-}
-
-static gboolean
-teco_qreg_bufferinfo_undo_set_integer(teco_qreg_t *qreg, GError **error)
-{
- return teco_current_doc_undo_edit(error);
+ return teco_current_doc_undo_edit(error) &&
+ teco_ring_edit(value, error);
}
static gboolean
@@ -703,7 +690,6 @@ teco_qreg_bufferinfo_new(void)
{
static teco_qreg_vtable_t vtable = TECO_INIT_QREG_EXTERNAL(
.set_integer = teco_qreg_bufferinfo_set_integer,
- .undo_set_integer = teco_qreg_bufferinfo_undo_set_integer,
.get_integer = teco_qreg_bufferinfo_get_integer,
.set_string = teco_qreg_bufferinfo_set_string,
.undo_set_string = teco_qreg_bufferinfo_undo_set_string,
@@ -1260,8 +1246,7 @@ teco_qreg_stack_pop(teco_qreg_t *qreg, GError **error)
teco_qreg_stack_entry_t *entry;
entry = &g_array_index(teco_qreg_stack, teco_qreg_stack_entry_t, teco_qreg_stack->len-1);
- if (!qreg->vtable->undo_set_integer(qreg, error) ||
- !qreg->vtable->set_integer(qreg, entry->integer, error))
+ if (!qreg->vtable->set_integer(qreg, entry->integer, error))
return FALSE;
/* exchange document ownership between stack entry and Q-Register */
diff --git a/src/qreg.h b/src/qreg.h
index c5e9461..ca35e78 100644
--- a/src/qreg.h
+++ b/src/qreg.h
@@ -47,17 +47,19 @@ extern teco_view_t *teco_qreg_view;
* teco_qreg_set_integer(qreg, 23, error);
*
* But this probably won't work. Perhaps use the X-macro pattern.
+ *
+ * FIXME: We can probably get rid of all the separate undo callbacks/methods.
*/
typedef const struct {
+ /* already pushes undo tokens */
gboolean (*set_integer)(teco_qreg_t *qreg, teco_int_t value, GError **error);
- gboolean (*undo_set_integer)(teco_qreg_t *qreg, GError **error);
gboolean (*get_integer)(teco_qreg_t *qreg, teco_int_t *ret, GError **error);
gboolean (*set_string)(teco_qreg_t *qreg, const gchar *str, gsize len,
guint codepage, GError **error);
gboolean (*undo_set_string)(teco_qreg_t *qreg, GError **error);
- /* does not need an explicit undo-call */
+ /* already pushes undo tokens */
gboolean (*append_string)(teco_qreg_t *qreg, const gchar *str, gsize len, GError **error);
gboolean (*get_string)(teco_qreg_t *qreg, gchar **str, gsize *len,
diff --git a/src/ring.c b/src/ring.c
index 548173b..ceeb730 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -736,19 +736,24 @@ teco_state_read_file_done(teco_machine_main_t *ctx, teco_string_t str, GError **
if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
- sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
- teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(pos);
+ sptr_t from = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ teco_undo_int(teco_ranges[0].from) = teco_current_doc_get_dot();;
g_autofree gchar *filename = teco_file_expand_path(str.data);
/* FIXME: Add wrapper to interface.h? */
if (!teco_view_load(teco_interface_current_view, filename, FALSE, error))
return NULL;
- pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
- teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs(pos);
+ /*
+ * FIXME: Perhaps teco_view_load() should return the number of glyphs added.
+ */
+ sptr_t to = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs_rel(teco_ranges[0].from,
+ from, to-from);
teco_undo_guint(teco_ranges_count) = 1;
if (teco_ranges[0].from != teco_ranges[0].to) {
+ teco_current_doc_set_dot(teco_ranges[0].to);
teco_ring_dirtify();
if (teco_current_doc_must_undo())
diff --git a/src/ring.h b/src/ring.h
index e45434d..91ce3c9 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -48,6 +48,12 @@ typedef struct teco_buffer_t {
* This is still a guint, so you can call teco_undo_guint().
*/
guint state;
+
+ /**
+ * Dot in glyphs.
+ * This field is always kept up to date.
+ */
+ teco_int_t dot;
} teco_buffer_t;
/** @memberof teco_buffer_t */
@@ -149,3 +155,23 @@ teco_current_doc_must_undo(void)
*/
return !teco_qreg_current || teco_qreg_current->must_undo;
}
+
+/** update dot in the current document (Q-Register or buffer) */
+static inline void
+teco_current_doc_set_dot(teco_int_t dot)
+{
+ if (teco_qreg_current) {
+ if (teco_qreg_current->must_undo)
+ teco_undo_int(teco_qreg_current->string.dot);
+ teco_qreg_current->string.dot = dot;
+ } else {
+ teco_undo_int(teco_ring_current->dot) = dot;
+ }
+}
+
+static inline teco_int_t
+teco_current_doc_get_dot(void)
+{
+ return teco_qreg_current ? teco_qreg_current->string.dot
+ : teco_ring_current->dot;
+}
diff --git a/src/search.c b/src/search.c
index 1ab925c..844c459 100644
--- a/src/search.c
+++ b/src/search.c
@@ -105,7 +105,6 @@ teco_state_control_search_mode(teco_machine_main_t *ctx, GError **error)
teco_expressions_push(search_mode);
} else {
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;
}
@@ -131,12 +130,12 @@ teco_state_search_initial(teco_machine_main_t *ctx, GError **error)
v1 = teco_expressions_pop_num(0);
if (v1 <= v2) {
teco_search_parameters.count = 1;
- teco_search_parameters.from = teco_interface_glyphs2bytes(v1);
- teco_search_parameters.to = teco_interface_glyphs2bytes(v2);
+ teco_search_parameters.from = teco_interface_glyphs2bytes_absdot(v1);
+ teco_search_parameters.to = teco_interface_glyphs2bytes_absdot(v2);
} else {
teco_search_parameters.count = -1;
- teco_search_parameters.from = teco_interface_glyphs2bytes(v2);
- teco_search_parameters.to = teco_interface_glyphs2bytes(v1);
+ teco_search_parameters.from = teco_interface_glyphs2bytes_absdot(v2);
+ teco_search_parameters.to = teco_interface_glyphs2bytes_absdot(v1);
}
if (teco_search_parameters.from < 0 ||
@@ -890,18 +889,21 @@ teco_do_search(regex_t *re, gsize from, gsize to, gint *count, GError **error)
/* match success */
g_assert(teco_ranges_count > 0);
- teco_interface_ssm(SCI_SETSEL, teco_ranges[0].from, teco_ranges[0].to);
+ gsize from = teco_ranges[0].from, to = teco_ranges[0].to;
/*
* teco_get_ranges() returned byte positions,
* while everything else expects glyph offsets.
* They are fixed up only now to avoid unnecessary
- * possibly costly teco_interface_bytes2glyphs() calls.
+ * possibly costly teco_interface_bytes2glyphs_absdot() calls.
*/
for (guint i = 0; i < teco_ranges_count; i++) {
- teco_ranges[i].from = teco_interface_bytes2glyphs(teco_ranges[i].from);
- teco_ranges[i].to = teco_interface_bytes2glyphs(teco_ranges[i].to);
+ teco_ranges[i].from = teco_interface_bytes2glyphs_absdot(teco_ranges[i].from);
+ teco_ranges[i].to = teco_interface_bytes2glyphs_absdot(teco_ranges[i].to);
}
+
+ teco_interface_ssm(SCI_SETSEL, from, to);
+ teco_current_doc_set_dot(teco_ranges[0].to);
}
return TRUE;
@@ -940,6 +942,7 @@ teco_state_search_process(teco_machine_main_t *ctx, teco_string_t str, gsize new
/*
* While SciTECO code is always guaranteed to be in valid UTF-8,
* the result of string building may not (eg. if ^EQq inserts garbage).
+ * terex does not currently reliably detect invalid UTF-8 sequences.
*/
g_set_error_literal(error, TECO_ERROR, TECO_ERROR_CODEPOINT,
"Invalid UTF-8 byte sequence in search pattern");
@@ -953,8 +956,7 @@ teco_state_search_process(teco_machine_main_t *ctx, teco_string_t str, gsize new
teco_qreg_t *search_reg = teco_qreg_table_find(&teco_qreg_table_globals, "_", 1);
g_assert(search_reg != NULL);
- if (!search_reg->vtable->undo_set_integer(search_reg, error) ||
- !search_reg->vtable->set_integer(search_reg, TECO_FAILURE, error))
+ if (!search_reg->vtable->set_integer(search_reg, TECO_FAILURE, error))
return FALSE;
g_autoptr(teco_machine_qregspec_t) qreg_machine;
@@ -1333,8 +1335,8 @@ teco_state_search_kill_done(teco_machine_main_t *ctx, teco_string_t str, GError
if (teco_search_parameters.dot < dot) {
/* kill forwards */
sptr_t anchor = teco_interface_ssm(SCI_GETANCHOR, 0, 0);
- teco_int_t len_glyphs = teco_interface_bytes2glyphs(anchor) -
- teco_interface_bytes2glyphs(teco_search_parameters.dot);
+ teco_int_t len_glyphs = teco_interface_bytes2glyphs_absdot(anchor) -
+ teco_interface_bytes2glyphs_absdot(teco_search_parameters.dot);
if (teco_current_doc_must_undo())
undo__teco_interface_ssm(SCI_GOTOPOS, dot, 0);
@@ -1353,8 +1355,13 @@ teco_state_search_kill_done(teco_machine_main_t *ctx, teco_string_t str, GError
teco_ranges[i].from -= len_glyphs;
teco_ranges[i].to -= len_glyphs;
}
+
+ g_assert(teco_ranges_count > 0);
+ teco_current_doc_set_dot(teco_ranges[0].from);
} else {
/* kill backwards */
+ teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(dot));
+
teco_interface_ssm(SCI_DELETERANGE, dot, teco_search_parameters.dot - dot);
/* NOTE: An undo action is not always created. */
@@ -1409,6 +1416,9 @@ teco_state_search_delete_done(teco_machine_main_t *ctx, teco_string_t str, GErro
return NULL;
if (teco_is_success(search_state)) {
+ sptr_t anchor = teco_interface_ssm(SCI_GETANCHOR, 0, 0);
+ teco_current_doc_set_dot(teco_interface_bytes2glyphs_absdot(anchor));
+
teco_interface_ssm(SCI_BEGINUNDOACTION, 0, 0);
teco_interface_ssm(SCI_REPLACESEL, 0, (sptr_t)"");
teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
@@ -1450,8 +1460,8 @@ teco_state_replace_insert_initial(teco_machine_main_t *ctx, GError **error)
* FIXME: Wastes undo tokens in teco_do_search().
* Perhaps make this configurable in the state.
*/
- 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_int(teco_ranges[0].to) = teco_ranges[0].from;
teco_undo_guint(teco_ranges_count) = 1;
/*
@@ -1531,7 +1541,8 @@ teco_state_replace_default_insert_done(teco_machine_main_t *ctx, teco_string_t s
teco_qreg_t *replace_reg = teco_qreg_table_find(&teco_qreg_table_globals, "-", 1);
g_assert(replace_reg != NULL);
- if (str.len > 0) {
+ gsize len = str.len;
+ if (len > 0) {
if (!replace_reg->vtable->undo_set_string(replace_reg, error) ||
!replace_reg->vtable->set_string(replace_reg, str.data, str.len,
teco_default_codepage(), error))
@@ -1542,10 +1553,18 @@ teco_state_replace_default_insert_done(teco_machine_main_t *ctx, teco_string_t s
NULL, error) ||
(replace_str.len > 0 && !teco_state_insert_process(ctx, replace_str, replace_str.len, error)))
return NULL;
+ len = replace_str.len;
}
+ /*
+ * 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-len, len);
+ teco_undo_int(teco_ranges[0].to) = to;
+ teco_current_doc_set_dot(to);
+
return &teco_state_start;
}
diff --git a/src/spawn.c b/src/spawn.c
index 0492bbf..b1cd305 100644
--- a/src/spawn.c
+++ b/src/spawn.c
@@ -222,8 +222,8 @@ teco_state_execute_initial(teco_machine_main_t *ctx, GError **error)
default:
/* pipe and replace character range */
- teco_spawn_ctx.to = teco_interface_glyphs2bytes(teco_expressions_pop_num(0));
- teco_spawn_ctx.from = teco_interface_glyphs2bytes(teco_expressions_pop_num(0));
+ teco_spawn_ctx.to = teco_interface_glyphs2bytes_absdot(teco_expressions_pop_num(0));
+ teco_spawn_ctx.from = teco_interface_glyphs2bytes_absdot(teco_expressions_pop_num(0));
rc = teco_bool(teco_spawn_ctx.from <= teco_spawn_ctx.to &&
teco_spawn_ctx.from >= 0 && teco_spawn_ctx.to >= 0);
}
@@ -424,6 +424,8 @@ teco_state_execute_done(teco_machine_main_t *ctx, teco_string_t str, GError **er
g_source_attach(teco_spawn_ctx.stdout_src, teco_spawn_ctx.mainctx);
if (!teco_spawn_ctx.register_argument) {
+ teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs_absdot(teco_spawn_ctx.from);
+
if (teco_current_doc_must_undo())
undo__teco_interface_ssm(SCI_GOTOPOS,
teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), 0);
@@ -438,9 +440,12 @@ teco_state_execute_done(teco_machine_main_t *ctx, teco_string_t str, GError **er
teco_spawn_ctx.to - teco_spawn_ctx.from);
sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
- teco_undo_int(teco_ranges[0].from) = teco_interface_bytes2glyphs(teco_spawn_ctx.from);
- teco_undo_int(teco_ranges[0].to) = teco_interface_bytes2glyphs(pos);
+ teco_int_t to = teco_interface_bytes2glyphs_rel(teco_ranges[0].from, teco_spawn_ctx.from,
+ pos - teco_spawn_ctx.from);
+ teco_undo_int(teco_ranges[0].to) = to;
teco_undo_guint(teco_ranges_count) = 1;
+
+ teco_current_doc_set_dot(to);
}
teco_interface_ssm(SCI_ENDUNDOACTION, 0, 0);
diff --git a/src/stdio-commands.c b/src/stdio-commands.c
index c2a1c16..34179c3 100644
--- a/src/stdio-commands.c
+++ b/src/stdio-commands.c
@@ -334,7 +334,7 @@ teco_state_start_typeout(teco_machine_main_t *ctx, GError **error)
{
gsize from, len;
- if (!teco_get_range_args("T", &from, &len, error))
+ if (!teco_get_range_args("T", NULL, &from, NULL, &len, error))
return;
/*
diff --git a/src/view.c b/src/view.c
index 8094186..7a9e0cc 100644
--- a/src/view.c
+++ b/src/view.c
@@ -644,27 +644,19 @@ teco_view_save_to_stdout(teco_view_t *ctx, GError **error)
/**
* Convert a glyph index to a byte offset as used by Scintilla.
*
- * This is optimized with the "line character index",
+ * This function is only for UTF-8 documents.
+ * It is optimized with the "line character index",
* which must always be enabled in UTF-8 documents.
*
- * It is also used to validate glyph indexes.
- *
* @param ctx The view to operate on.
* @param pos Position in glyphs/characters.
* @return Position in bytes or -1 if pos is out of bounds.
*/
-gssize
-teco_view_glyphs2bytes(teco_view_t *ctx, teco_int_t pos)
+static gssize
+teco_view_glyphs2bytes_unicode(teco_view_t *ctx, teco_int_t pos)
{
if (pos < 0)
- return -1; /* invalid position */
- if (!pos)
- return 0;
-
- if (!(teco_view_ssm(ctx, SCI_GETLINECHARACTERINDEX, 0, 0) &
- SC_LINECHARACTERINDEX_UTF32))
- /* assume single-byte encoding */
- return pos <= teco_view_ssm(ctx, SCI_GETLENGTH, 0, 0) ? pos : -1;
+ return -1;
sptr_t line = teco_view_ssm(ctx, SCI_LINEFROMINDEXPOSITION, pos,
SC_LINECHARACTERINDEX_UTF32);
@@ -675,19 +667,16 @@ teco_view_glyphs2bytes(teco_view_t *ctx, teco_int_t pos)
}
/**
- * Convert byte offset to glyph/character index without bounds checking.
+ * Convert a bytes index to a glyph offset.
+ *
+ * This function is only for UTF-8 documents.
+ * It is optimized with the "line character index",
+ * which must always be enabled in UTF-8 documents.
+ * This function does \b not check for invalid positions.
*/
-teco_int_t
-teco_view_bytes2glyphs(teco_view_t *ctx, gsize pos)
+static teco_int_t
+teco_view_bytes2glyphs_unicode(teco_view_t *ctx, gsize pos)
{
- if (!pos)
- return 0;
-
- if (!(teco_view_ssm(ctx, SCI_GETLINECHARACTERINDEX, 0, 0) &
- SC_LINECHARACTERINDEX_UTF32))
- /* assume single-byte encoding */
- return pos;
-
sptr_t line = teco_view_ssm(ctx, SCI_LINEFROMPOSITION, pos, 0);
sptr_t line_bytes = teco_view_ssm(ctx, SCI_POSITIONFROMLINE, line, 0);
return teco_view_ssm(ctx, SCI_INDEXPOSITIONFROMLINE, line,
@@ -698,7 +687,7 @@ teco_view_bytes2glyphs(teco_view_t *ctx, gsize pos)
#define TECO_RELATIVE_LIMIT 1024
/**
- * Convert a glyph index relative to a byte position to
+ * Convert a glyph index relative to a position to
* a byte position.
*
* Can be used to implement commands with relative character
@@ -709,23 +698,87 @@ teco_view_bytes2glyphs(teco_view_t *ctx, gsize pos)
* (as on exceedingly long lines).
*
* @param ctx The view to operate on.
+ * @param pos_glyphs Glyph position to start.
+ * It must be the same position as specified by pos.
* @param pos Byte position to start.
* @param n Number of glyphs/characters to the left (negative) or
- * right (positive) of pos.
+ * right (positive) of pos_glyphs and pos.
* @return Position in bytes or -1 if the resulting position is out of bounds.
*/
gssize
-teco_view_glyphs2bytes_relative(teco_view_t *ctx, gsize pos, teco_int_t n)
+teco_view_glyphs2bytes_rel(teco_view_t *ctx, teco_int_t pos_glyphs, gsize pos, teco_int_t n)
{
- if (!n)
+ if (n == 0)
return pos;
+ if (pos_glyphs == -n)
+ return 0;
+
+ if (!(teco_view_ssm(ctx, SCI_GETLINECHARACTERINDEX, 0, 0) &
+ SC_LINECHARACTERINDEX_UTF32)) {
+ /* assume single-byte encoding */
+ g_assert(pos_glyphs == pos);
+
+ sptr_t len = teco_view_ssm(ctx, SCI_GETLENGTH, 0, 0);
+ if (0 > (gssize)pos+n || (gssize)pos+n > len)
+ return -1;
+
+ return pos+n;
+ }
+
/* NOTE: Does not work for n == G_MININT64. */
if (ABS(n) > TECO_RELATIVE_LIMIT)
- return teco_view_glyphs2bytes(ctx, teco_view_bytes2glyphs(ctx, pos) + n);
+ return teco_view_glyphs2bytes_unicode(ctx, pos_glyphs+n);
sptr_t res = teco_view_ssm(ctx, SCI_POSITIONRELATIVE, pos, n);
/* SCI_POSITIONRELATIVE may return 0 even if the offset is valid */
- return res ? : n > 0 ? -1 : teco_view_bytes2glyphs(ctx, pos)+n >= 0 ? 0 : -1;
+ return res ? : n > 0 ? -1 : pos_glyphs + n >= 0 ? 0 : -1;
+}
+
+/**
+ * Convert a byte index relative to a known position to
+ * a glyph position.
+ *
+ * Can be used to implement commands with relative character
+ * ranges.
+ * As an optimization, this always counts characters for deltas
+ * smaller than TECO_RELATIVE_LIMIT, so it will be fast
+ * even where the character-index based lookup is too slow
+ * (as on exceedingly long lines).
+ *
+ * @param ctx The view to operate on.
+ * @param pos_glyphs Glyph position to start.
+ * It must be the same position as specified by pos.
+ * @param pos Byte position to start.
+ * @param n Number of bytes to the left (negative) or
+ * right (positive) of pos_glyphs and pos.
+ * @return Position in glyphs or -1 if the resulting position is out of bounds.
+ */
+teco_int_t
+teco_view_bytes2glyphs_rel(teco_view_t *ctx, teco_int_t pos_glyphs, gsize pos, gssize n)
+{
+ if (n == 0)
+ return pos_glyphs;
+ if (pos == -n)
+ return 0;
+
+ sptr_t len = teco_view_ssm(ctx, SCI_GETLENGTH, 0, 0);
+
+ if (0 > (gssize)pos+n || (gssize)pos+n > len)
+ return -1;
+
+ if (!(teco_view_ssm(ctx, SCI_GETLINECHARACTERINDEX, 0, 0) &
+ SC_LINECHARACTERINDEX_UTF32)) {
+ /* assume single-byte encoding */
+ g_assert(pos_glyphs == pos);
+ return pos_glyphs+n;
+ }
+
+ /* NOTE: Does not work for n == G_MINSSIZE. */
+ if (ABS(n) > TECO_RELATIVE_LIMIT)
+ return teco_view_bytes2glyphs_unicode(ctx, pos+n);
+
+ return n < 0 ? pos_glyphs - teco_view_ssm(ctx, SCI_COUNTCHARACTERS, pos+n, pos)
+ : pos_glyphs + teco_view_ssm(ctx, SCI_COUNTCHARACTERS, pos, pos+n);
}
/**
diff --git a/src/view.h b/src/view.h
index 4c57eb8..86cc3dc 100644
--- a/src/view.h
+++ b/src/view.h
@@ -85,9 +85,10 @@ teco_view_get_codepage(teco_view_t *ctx)
? : teco_view_ssm(ctx, SCI_STYLEGETCHARACTERSET, STYLE_DEFAULT, 0);
}
-gssize teco_view_glyphs2bytes(teco_view_t *ctx, teco_int_t pos);
-teco_int_t teco_view_bytes2glyphs(teco_view_t *ctx, gsize pos);
-gssize teco_view_glyphs2bytes_relative(teco_view_t *ctx, gsize pos, teco_int_t n);
+gssize teco_view_glyphs2bytes_rel(teco_view_t *ctx, teco_int_t pos_glyphs,
+ gsize pos, teco_int_t n);
+teco_int_t teco_view_bytes2glyphs_rel(teco_view_t *ctx, teco_int_t pos_glyphs,
+ gsize pos, gssize n);
teco_int_t teco_view_get_character(teco_view_t *ctx, gsize pos, gsize len);
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 95c1336..cbb12d4 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -274,15 +274,15 @@ TE_CHECK([[@EB'words-example.txt' Z-4J 2Y .-18"N(0/0)' 2C @Y Z-19"N(0/0)']], 0,
AT_CLEANUP
AT_SETUP([Searches])
-# FIXME: We cannot currently easily insert a single ASCII 5 (^E), as it must be followed
-# by a 2nd character. It can be quoted, but cannot be written as Caret+E.
-# You also cannot search for a single ASCII 5 using Caret+E.
-# 2 additional ^Q are translated to a single ^Q and interpreted at the search-pattern layer.
-TE_CHECK(m4_format([[@I/^Q%c/ J @:S/^Q^Q^Q%c/"F(0/0)']], 5, 5), 0, ignore, ignore)
+# Searching for ^E (5)
+TE_CHECK([[5@I// J @:S/^Q^Q^E<5>/"F(0/0)']], 0, ignore, ignore)
+TE_CHECK([[@I/АБВГД/ J :@S/в/"F(0/0)' .-3"N(0/0)']], 0, ignore, ignore)
# Canse-sensitive search
TE_CHECK([[@I/XXX/J -^X @:S/xxx/"S(0/0)']], 0, ignore, ignore)
+TE_CHECK([[@I/АБВГД/J -^X :@S/в/"S(0/0)']], 0, ignore, ignore)
# Search mode should be local to the macro frame.
TE_CHECK([[-^X @^Um{^X} Mm-0"N(0/0)']], 0, ignore, ignore)
+# Anchored search
TE_CHECK([[@I/XYZ/ J ::@S/X/"F(0/0)' H::@S/Z/"S(0/0)']], 0, ignore, ignore)
AT_CLEANUP
@@ -312,6 +312,13 @@ AT_DATA([test.txt], [[0123456789
TE_CHECK([[@ER"test.txt" ^S+11"N(0/0)']], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Globbing])
+# This is from the source tree - there should be plenty of lexers
+TE_CHECK([[1@EN|^EN[$SCITECOPATH]/lexers/*.tes|| ."=(0/0)' :^Q-50"<(0/0)']], 0, ignore, ignore)
+TE_CHECK([[1:@EN|^EN[$srcdir]/*.in||"F(0/0)']], 0, ignore, ignore)
+TE_CHECK([[:@EN/[аб]?/бЖ/"F(0/0)']], 0, ignore, ignore)
+AT_CLEANUP
+
AT_SETUP([Macro calls])
TE_CHECK([[@^Ua{-$$} Ma+1"N(0/0)']], 0, ignore, ignore)
AT_CLEANUP
@@ -387,6 +394,11 @@ TE_CHECK([[0EE 255@I/A/J 65001EE 0A-(-2)"N(0/0)' 1A-^^A"N(0/0)' 2A-(-1)"N(0/0)']
TE_CHECK([[@EQa// 0EE 128@I/A/J 65001EE 0Qa-(-2)"N(0/0)' 1Qa-^^A"N(0/0)' 2Qa-(-1)"N(0/0)']], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Glyphs to byte heuristics])
+# Should be fast.
+TE_CHECK([[100000<@I"Ж"> J<:C;> J<.-1:J;> .*2-^E"N(0/0)']], 0, ignore, ignore)
+AT_CLEANUP
+
AT_SETUP([Automatic EOL normalization])
TE_CHECK([[@EB'^EQ[$srcdir]/autoeol-input.txt' EL-2"N(0/0)' 2LR 13@I'' 0EL @EW'autoeol-sciteco.txt']],
0, ignore, ignore)
@@ -535,9 +547,7 @@ AT_CLEANUP
# It could fail because the memory limit is exceeed,
# but not in this case since the match string isn't too large.
AT_SETUP([Pattern matching overflow])
-# NOTE: Creating very long lines would currently be ineffective
-# at least in UTF-8 mode.
-TE_CHECK([[100000<@I"^J">J @S"^EM^X"]], 0, ignore, ignore)
+TE_CHECK([[100000<@I"X">J @S"^EM^X"]], 0, ignore, ignore)
AT_CLEANUP
AT_SETUP([Block-wise backwards search])