diff options
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | doc/sciteco.7.template | 6 | ||||
-rw-r--r-- | src/core-commands.c | 4 | ||||
-rw-r--r-- | src/parser.c | 120 |
4 files changed, 104 insertions, 31 deletions
@@ -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; } |