aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2024-12-08 05:22:17 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2024-12-08 16:10:29 +0300
commitbd87ff40e73929e761e1233aa812a6736cacbed1 (patch)
tree2023be5c0fbe9f81aacf176c05fce740f35f0381
parente5884ab2166ab5a03294baa54601b8785e6d9727 (diff)
downloadsciteco-bd87ff40e73929e761e1233aa812a6736cacbed1.tar.gz
implemented the ^Q command for converting between line and glyph positions
* As known from DEC TECO, but extended to convert absolute positions to line numbers as well. :^Q returns the current line. * Especially useful in macros that accept line arguments, as it is much shorter than something like ^E@ES/LINEFROMPOSITION//+Q.l@ES/POSITIONFROMLINE//:^E-. * On the other hand, the fact that ^Q checks the line range means we cannot easily replace lexer.checkheader with something like [:J 0,^Q::S...$ ]: Using SCI_POSITIONFROMLINE still has the advantage that it returns `Z` for out-of-bounds ranges which would be cumbersome to write with the current ^Q. * Perhaps there should be a separate command for converting between absolute lines and positions and :^Q should be repurposed to return a failure boolean for out-of-range values? * fnkeys.tes could be simplified.
-rw-r--r--lib/fnkeys.tes12
-rwxr-xr-xlib/scite2co.lua2
-rw-r--r--src/core-commands.c65
-rw-r--r--tests/testsuite.at4
4 files changed, 76 insertions, 7 deletions
diff --git a/lib/fnkeys.tes b/lib/fnkeys.tes
index fd6b332..ab78025 100644
--- a/lib/fnkeys.tes
+++ b/lib/fnkeys.tes
@@ -36,7 +36,7 @@
*!
@[HOME]{
- ESLINEFROMPOSITIONESPOSITIONFROMLINE:U.p
+ 0+.U.p
Q.pU.l <Q.l-."U 1; ' Q.l-.AU.c Q.c- "N Q.c-9"N Q.lU.p 1; '' %.l>
Q.pESGETCOLUMN,4EJ
Q.p-.M#c
@@ -45,7 +45,7 @@
1U[ HOME]
@[END]{
- ESLINEFROMPOSITIONESGETLINEENDPOSITIONU.p
+ :-1ESGETLINEENDPOSITIONU.p
Q.pESGETCOLUMN,4EJ
Q.p:-.M#c
}
@@ -54,7 +54,7 @@
@[NPAGE]{
0,4EJ
- ESLINEFROMPOSITION+(ESLINESONSCREEN)
+ :-1+ESLINESONSCREEN
ESPOSITIONFROMLINEU.p
Q.p"< Z | Q.p: '-.M#c
}
@@ -63,7 +63,7 @@
@[PPAGE]{
0,4EJ
- ESLINEFROMPOSITION-(ESLINESONSCREEN)U.l
+ :-1-ESLINESONSCREENU.l
Q.l"< 0 | Q.lESPOSITIONFROMLINE: '-.M#c
}
@[ PPAGE]{(M[PPAGE]}
@@ -102,13 +102,13 @@
1U[ SRIGHT]
@[UP]{
- 4EJ(ESLINEFROMPOSITION-1)ESFINDCOLUMN:-.M#c
+ 4EJ,:-2ESFINDCOLUMN:-.M#c
}
@[ UP]{(M[UP]}
1U[ UP]
@[DOWN]{
- 4EJ(ESLINEFROMPOSITION+1)ESFINDCOLUMN:-.M#c
+ 4EJ,:ESFINDCOLUMN:-.M#c
}
@[ DOWN]{(M[DOWN]}
1U[ DOWN]
diff --git a/lib/scite2co.lua b/lib/scite2co.lua
index 7c49aaa..ab3ccf4 100755
--- a/lib/scite2co.lua
+++ b/lib/scite2co.lua
@@ -107,7 +107,7 @@ local file_patterns = expand(props["file.patterns."..language])
io.write([=[
@[lexer.test.]=], language:lower(), [=[]{
]=])
-if shbang then io.write([=[ _#!M]=], shbang, [=[M[lexer.checkheader]"S -1 '
+if shbang then io.write([=[ _#!M]=], shbang, [=[:M[lexer.checkheader]"S -1 '
]=]) end
local patterns = {}
for pattern in file_patterns:gmatch("[^;]+") do
diff --git a/src/core-commands.c b/src/core-commands.c
index 6e39d9a..2f473ce 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -1672,6 +1672,9 @@ teco_state_control_negate(teco_machine_main_t *ctx, GError **error)
{
teco_int_t v;
+ if (!teco_expressions_eval(FALSE, error))
+ return;
+
if (!teco_expressions_args()) {
teco_error_argexpected_set(error, "^_");
return;
@@ -1788,6 +1791,67 @@ teco_state_control_radix(teco_machine_main_t *ctx, GError **error)
}
}
+/*$ ^Q lines2glyphs glyphs2lines
+ * [n]^Q -> glyphs -- Convert between lines and glyph lengths or positions
+ * [position]:^Q -> line
+ *
+ * Converts between line and glyph arguments.
+ * It returns the number of glyphs between dot and the <n>-th next
+ * line (or previous line if <n> is negative).
+ * Consequently \(lq^QC\(rq is equivalent to \(lqL\(rq, but less efficient.
+ *
+ * If colon-modified, an absolute buffer position is converted to the line that
+ * contains this position, beginning with 1.
+ * Without arguments, \(lq:^Q\(rq returns the current line.
+ */
+/*
+ * FIXME: Perhaps there should be a way to convert an absolute line to an
+ * absolute position.
+ */
+static void
+teco_state_control_lines2glyphs(teco_machine_main_t *ctx, GError **error)
+{
+ if (!teco_expressions_eval(FALSE, error))
+ return;
+
+ if (teco_machine_main_eval_colon(ctx)) {
+ gssize pos;
+
+ if (!teco_expressions_args()) {
+ pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ } else {
+ teco_int_t v;
+
+ if (!teco_expressions_pop_num_calc(&v, 0, error))
+ return;
+
+ pos = teco_interface_glyphs2bytes(v);
+ if (pos < 0) {
+ teco_error_range_set(error, "^Q");
+ return;
+ }
+ }
+
+ teco_expressions_push(teco_interface_ssm(SCI_LINEFROMPOSITION, pos, 0)+1);
+ } else {
+ teco_int_t v;
+
+ if (!teco_expressions_pop_num_calc(&v, teco_num_sign, error))
+ return;
+
+ sptr_t pos = teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0);
+ sptr_t line = teco_interface_ssm(SCI_LINEFROMPOSITION, pos, 0) + v;
+
+ if (!teco_validate_line(line)) {
+ teco_error_range_set(error, "^Q");
+ return;
+ }
+
+ sptr_t line_pos = teco_interface_ssm(SCI_POSITIONFROMLINE, line, 0);
+ teco_expressions_push(teco_interface_bytes2glyphs(line_pos) - teco_interface_bytes2glyphs(pos));
+ }
+}
+
/*$ ^E glyphs2bytes bytes2glyphs
* glyphs^E -> bytes -- Translate between glyph and byte indexes
* bytes:^E -> glyphs
@@ -1975,6 +2039,7 @@ teco_state_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
['O'] = {&teco_state_start, teco_state_control_octal},
['D'] = {&teco_state_start, teco_state_control_decimal},
['R'] = {&teco_state_start, teco_state_control_radix},
+ ['Q'] = {&teco_state_start, teco_state_control_lines2glyphs},
['E'] = {&teco_state_start, teco_state_control_glyphs2bytes},
['X'] = {&teco_state_start, teco_state_control_search_mode},
['Y'] = {&teco_state_start, teco_state_control_last_range},
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 00861dc..ffb3941 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -109,6 +109,10 @@ AT_CHECK([$SCITECO -e "[[\$ @FG'..' ]]\$ :Q\$-1Q\$-^^r\"=(0/0)'"], 0, ignore, ig
AT_CHECK([$SCITECO -e "[[: @I/XXX/ ]]: .\"N(0/0)'"], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Convert between line and glyph positions])
+AT_CHECK([$SCITECO -e "@I/1^J2^J3/J 2^QC :^Q-3\"N(0/0)'"], 0, ignore, ignore)
+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.