aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2024-09-20 13:50:13 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2024-09-20 13:50:13 +0200
commit2b5b2a48f8db3d6b73a0f1a6e0aeab3a940b3b85 (patch)
tree69e7a54ffb98301607ea9ebde4a2715fa146c3fc
parentfcf962edded2d6a7cb638909587167261e4f2bb0 (diff)
downloadsciteco-2b5b2a48f8db3d6b73a0f1a6e0aeab3a940b3b85.tar.gz
^W^W and ^V^V can be typed completely with upcarets now and they case fold all expansions of ^EQq, ^EUq and so on
* Previously, there was no way to enter upper-case mode in interactive commands since the Ctrl+W immediate editing command is interpreted everywhere. * Without the case folding of ^EQq/^EUq results, the upper and lower case modes are actually pretty useless considering that modern keyboards have caps lock. So it was clear we need this, regardless of what the classic TECOs did. The TECO-11 manual is not very clear on this. tecoc apparently does not case-fold ^EQq results. * This opens up new idioms, for instance `EUq^W^W^EQq$` in order to upper case register q. It's also the only way you can currently upper-case Unicode codepoints.
-rw-r--r--TODO5
-rw-r--r--doc/sciteco.7.template6
-rw-r--r--src/core-commands.c4
-rw-r--r--src/parser.c120
4 files changed, 104 insertions, 31 deletions
diff --git a/TODO b/TODO
index 0487a65..c4be13b 100644
--- a/TODO
+++ b/TODO
@@ -133,11 +133,6 @@ Known Bugs:
able to autocomplete it if a previous autocompletion inserted
escaped glob patterns.
Unfortunately, this would be very tricky to do right.
- * There is no way to type the ^W^W string building character,
- not even with upcarets.
- * ^V and ^W string building characters do not operate
- on ^EQq and ^EUq, which is a pity as that would be the
- only sane use for them.
* The unnamed buffer hasn't got margins set.
Should be fixed in sample.teco_ini.
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index 52fa742..193d029 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -1688,15 +1688,19 @@ character, so for instance \(lq^Q^Q\(rq translates to \(lq^Q\(rq.
.B ^V^V
.TQ
.BI ^V c
-Translates all following characters into lower case.
+Translates all following characters, including the expansions of \fB^EQ\fP,
+\fB^EU\fP etc., into lower case.
When \fB^V\fP is not followed by \fB^V\fP, a single character
\fIc\fP is lower-cased.
+\# Which is pretty pointless nowadays.
.TP
.SCITECO_TOPIC ^W^W ^Wc
.B ^W^W
.TQ
.BI ^W c
Analogous to \fB^V\fP, but upper-cases characters.
+Since \fB^W\fP is an immediate editing command, this can practically be typed
+only with upcarets in interactive mode.
.TP
.SCITECO_TOPIC ^E\[rs] ^E\[rs]q
.BI ^E\(rs q
diff --git a/src/core-commands.c b/src/core-commands.c
index fb8f142..300ffef 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -2838,8 +2838,8 @@ teco_state_insert_process(teco_machine_main_t *ctx, const teco_string_t *str,
* Secondly, the command inserts <text>.
* In interactive mode, <text> is inserted interactively.
*
- * String building characters are \fBenabled\fP for the
- * I command.
+ * Unlike in classic TECO dialects, string building characters are
+ * \fBenabled\fP for the \fBI\fP command.
* When editing \*(ST macros, using the \fBEI\fP command
* may be better, since it has string building characters
* disabled.
diff --git a/src/parser.c b/src/parser.c
index e73c877..15d9f5e 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -359,6 +359,31 @@ teco_machine_main_clear(teco_machine_main_t *ctx)
teco_machine_stringbuilding_clear(&ctx->expectstring.machine);
}
+/** Append string to result with case folding. */
+static void
+teco_machine_stringbuilding_append(teco_machine_stringbuilding_t *ctx, const gchar *str, gsize len)
+{
+ g_assert(ctx->result != NULL);
+
+ switch (ctx->mode) {
+ case TECO_STRINGBUILDING_MODE_NORMAL:
+ teco_string_append(ctx->result, str, len);
+ break;
+ case TECO_STRINGBUILDING_MODE_UPPER: {
+ g_autofree gchar *folded = ctx->codepage == SC_CP_UTF8
+ ? g_utf8_strup(str, len) : g_ascii_strup(str, len);
+ teco_string_append(ctx->result, folded, strlen(folded));
+ break;
+ }
+ case TECO_STRINGBUILDING_MODE_LOWER: {
+ g_autofree gchar *folded = ctx->codepage == SC_CP_UTF8
+ ? g_utf8_strdown(str, len) : g_ascii_strdown(str, len);
+ teco_string_append(ctx->result, folded, strlen(folded));
+ break;
+ }
+ }
+}
+
/*
* FIXME: All teco_state_stringbuilding_* states could be static?
*/
@@ -458,6 +483,8 @@ teco_state_stringbuilding_escaped_input(teco_machine_stringbuilding_t *ctx, guni
* is that we don't try to casefold non-ANSI characters in single-byte mode.
*/
switch (ctx->mode) {
+ case TECO_STRINGBUILDING_MODE_NORMAL:
+ break;
case TECO_STRINGBUILDING_MODE_UPPER:
chr = ctx->codepage == SC_CP_UTF8 || chr < 0x80
? g_unichar_toupper(chr) : chr;
@@ -466,8 +493,6 @@ teco_state_stringbuilding_escaped_input(teco_machine_stringbuilding_t *ctx, guni
chr = ctx->codepage == SC_CP_UTF8 || chr < 0x80
? g_unichar_tolower(chr) : chr;
break;
- default:
- break;
}
teco_string_append_wc(ctx->result, chr);
@@ -477,50 +502,82 @@ teco_state_stringbuilding_escaped_input(teco_machine_stringbuilding_t *ctx, guni
TECO_DEFINE_STATE(teco_state_stringbuilding_escaped);
static teco_state_t *
-teco_state_stringbuilding_lower_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
+teco_state_stringbuilding_lower_ctl_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
{
if (!ctx->result)
/* parse-only mode */
return &teco_state_stringbuilding_start;
- /*
- * FIXME: This does not handle ^V^V typed with up-carets.
- */
- if (chr == TECO_CTL_KEY('V')) {
+ chr = teco_ascii_toupper(chr);
+
+ if (chr == 'V') {
if (ctx->parent.must_undo)
teco_undo_guint(ctx->mode);
ctx->mode = TECO_STRINGBUILDING_MODE_LOWER;
} else {
+ /* control keys cannot be case folded */
+ teco_string_append_wc(ctx->result, TECO_CTL_KEY(chr));
+ }
+
+ return &teco_state_stringbuilding_start;
+}
+
+TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_lower_ctl);
+
+static teco_state_t *
+teco_state_stringbuilding_lower_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
+{
+ if (chr == '^')
+ return &teco_state_stringbuilding_lower_ctl;
+ if (TECO_IS_CTL(chr))
+ return teco_state_stringbuilding_lower_ctl_input(ctx, TECO_CTL_ECHO(chr), error);
+
+ if (ctx->result) {
chr = ctx->codepage == SC_CP_UTF8 || chr < 0x80
? g_unichar_tolower(chr) : chr;
teco_string_append_wc(ctx->result, chr);
}
-
return &teco_state_stringbuilding_start;
}
TECO_DEFINE_STATE(teco_state_stringbuilding_lower);
static teco_state_t *
-teco_state_stringbuilding_upper_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
+teco_state_stringbuilding_upper_ctl_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
{
if (!ctx->result)
/* parse-only mode */
return &teco_state_stringbuilding_start;
- /*
- * FIXME: This does not handle ^W^W typed with up-carets.
- */
- if (chr == TECO_CTL_KEY('W')) {
+ chr = teco_ascii_toupper(chr);
+
+ if (chr == 'W') {
if (ctx->parent.must_undo)
teco_undo_guint(ctx->mode);
ctx->mode = TECO_STRINGBUILDING_MODE_UPPER;
} else {
+ /* control keys cannot be case folded */
+ teco_string_append_wc(ctx->result, TECO_CTL_KEY(chr));
+ }
+
+ return &teco_state_stringbuilding_start;
+}
+
+TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_upper_ctl);
+
+static teco_state_t *
+teco_state_stringbuilding_upper_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
+{
+ if (chr == '^')
+ return &teco_state_stringbuilding_upper_ctl;
+ if (TECO_IS_CTL(chr))
+ return teco_state_stringbuilding_upper_ctl_input(ctx, TECO_CTL_ECHO(chr), error);
+
+ if (ctx->result) {
chr = ctx->codepage == SC_CP_UTF8 || chr < 0x80
? g_unichar_toupper(chr) : chr;
teco_string_append_wc(ctx->result, chr);
}
-
return &teco_state_stringbuilding_start;
}
@@ -541,7 +598,7 @@ teco_state_stringbuilding_ctle_input(teco_machine_stringbuilding_t *ctx, gunicha
if (ctx->result) {
gchar buf[1+6] = {TECO_CTL_KEY('E')};
gsize len = g_unichar_to_utf8(chr, buf+1);
- teco_string_append(ctx->result, buf, 1+len);
+ teco_machine_stringbuilding_append(ctx, buf, 1+len);
}
return &teco_state_stringbuilding_start;
}
@@ -601,7 +658,7 @@ teco_state_stringbuilding_ctle_num_input(teco_machine_stringbuilding_t *ctx, gun
*/
gchar buffer[TECO_EXPRESSIONS_FORMAT_LEN];
const gchar *num = teco_expressions_format(buffer, value);
- teco_string_append(ctx->result, num, strlen(num));
+ teco_machine_stringbuilding_append(ctx, num, strlen(num));
return &teco_state_stringbuilding_start;
}
@@ -634,11 +691,31 @@ teco_state_stringbuilding_ctle_u_input(teco_machine_stringbuilding_t *ctx, gunic
if (ctx->codepage == SC_CP_UTF8) {
if (value < 0 || !g_unichar_validate(value))
goto error_codepoint;
+ switch (ctx->mode) {
+ case TECO_STRINGBUILDING_MODE_NORMAL:
+ break;
+ case TECO_STRINGBUILDING_MODE_UPPER:
+ value = g_unichar_toupper(value);
+ break;
+ case TECO_STRINGBUILDING_MODE_LOWER:
+ value = g_unichar_tolower(value);
+ break;
+ }
teco_string_append_wc(ctx->result, value);
} else {
if (value < 0 || value > 0xFF)
goto error_codepoint;
- teco_string_append_c(ctx->result, (gchar)value);
+ switch (ctx->mode) {
+ case TECO_STRINGBUILDING_MODE_NORMAL:
+ break;
+ case TECO_STRINGBUILDING_MODE_UPPER:
+ value = g_ascii_toupper(value);
+ break;
+ case TECO_STRINGBUILDING_MODE_LOWER:
+ value = g_ascii_tolower(value);
+ break;
+ }
+ teco_string_append_c(ctx->result, value);
}
return &teco_state_stringbuilding_start;
@@ -672,13 +749,10 @@ teco_state_stringbuilding_ctle_q_input(teco_machine_stringbuilding_t *ctx, gunic
/* parse-only mode */
return &teco_state_stringbuilding_start;
- /*
- * FIXME: Should we have a special teco_qreg_get_string_append() function?
- */
g_auto(teco_string_t) str = {NULL, 0};
if (!qreg->vtable->get_string(qreg, &str.data, &str.len, NULL, error))
return NULL;
- teco_string_append(ctx->result, str.data, str.len);
+ teco_machine_stringbuilding_append(ctx, str.data, str.len);
return &teco_state_stringbuilding_start;
}
@@ -720,7 +794,7 @@ teco_state_stringbuilding_ctle_quote_input(teco_machine_stringbuilding_t *ctx, g
return NULL;
}
g_autofree gchar *str_quoted = g_shell_quote(str.data ? : "");
- teco_string_append(ctx->result, str_quoted, strlen(str_quoted));
+ teco_machine_stringbuilding_append(ctx, str_quoted, strlen(str_quoted));
return &teco_state_stringbuilding_start;
}
@@ -757,7 +831,7 @@ teco_state_stringbuilding_ctle_n_input(teco_machine_stringbuilding_t *ctx, gunic
}
g_autofree gchar *str_escaped = teco_globber_escape_pattern(str.data);
- teco_string_append(ctx->result, str_escaped, strlen(str_escaped));
+ teco_machine_stringbuilding_append(ctx, str_escaped, strlen(str_escaped));
return &teco_state_stringbuilding_start;
}