From bd87ff40e73929e761e1233aa812a6736cacbed1 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 8 Dec 2024 05:22:17 +0300 Subject: 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. --- lib/fnkeys.tes | 12 +++++----- lib/scite2co.lua | 2 +- src/core-commands.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 4 ++++ 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.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 -th next + * line (or previous line if 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. -- cgit v1.2.3