aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <rhaberkorn@fmsbw.de>2026-07-26 02:36:20 +0200
committerRobin Haberkorn <rhaberkorn@fmsbw.de>2026-07-26 12:28:34 +0200
commit68364bd3637b6944fa1f63a00dae5caf375afab9 (patch)
tree1a6ff54138f6229cbea51a8999df297b9ce90f00
parenta07512149088ec8bb47d16ed8fbbfdefd4745626 (diff)
conditionals can be terminated with F" now in addition to a single-quote (')
This is useful when writing small macros directly on the command-line as in `sciteco --eval`. If you use double quoted shell strings, too many characters have to be escaped. If you use single-quotes, though, embedding the conditional end (') is annoying -- it would have to be written as '\''.
-rw-r--r--doc/sciteco.7.template5
-rw-r--r--src/core-commands.c70
-rw-r--r--src/error.h4
-rw-r--r--src/parser.c3
-rw-r--r--tests/testsuite.at5
5 files changed, 55 insertions, 32 deletions
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index a3139bf..9d257a2 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -2337,7 +2337,7 @@ They are described in the reference section of this manual.
.SS Conditionals
.\" NOTE: Two quoted double-quotes are necessary to escape
.\" a single double quote in macro arguments
-.SCITECO_TOPIC """" conditional if then else
+.SCITECO_TOPIC """" "|" "'" "F""" conditional if then else
.
Last but not least, \*(ST supports so called conditionals.
They correspond to structured IF-THEN-ELSE statements
@@ -2359,6 +2359,9 @@ stack \(em the remaining arguments may be evaluated by the
Values accumulated on the expression stack by the \fIif\fP or \fIelse\fP
blocks are not discarded by the terminating single-quote.
In other words, conditionals may also return values.
+Instead of a single quote, \(lqF"\(rq can also be used to terminate
+the conditional \(em this can be handy when passing \*(ST scripts
+on the command line, e.g. after \(lq\-\-eval\(rq.
The possible conditions are defined in the following list.
Unless \fIn\fP is defined optional, the conditionals described
below yield an error if \fIn\fP is omitted:
diff --git a/src/core-commands.c b/src/core-commands.c
index 58a1ea2..32381f7 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -52,6 +52,7 @@
static teco_state_t *teco_state_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error);
static teco_state_t *teco_state_ctlc_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error);
+static teco_state_t *teco_state_endcond(teco_machine_main_t *ctx, const gchar *cmd, GError **error);
/**
* Translate buffer range arguments from the expression stack to
@@ -750,7 +751,8 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
if (teco_is_noop(chr)) {
if (ctx->flags.modifier_at ||
(ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) {
- teco_error_modifier_set(error, chr);
+ gchar cmd[] = {chr, '\0'};
+ teco_error_modifier_set(error, cmd);
return NULL;
}
return &teco_state_start;
@@ -776,7 +778,8 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
case '0' ... '9':
if (ctx->flags.modifier_at ||
(ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) {
- teco_error_modifier_set(error, chr);
+ gchar cmd[] = {chr, '\0'};
+ teco_error_modifier_set(error, cmd);
return NULL;
}
if (ctx->flags.mode == TECO_MODE_NORMAL)
@@ -835,7 +838,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
case '|':
if (ctx->flags.modifier_at ||
(ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) {
- teco_error_modifier_set(error, '|');
+ teco_error_modifier_set(error, "|");
return NULL;
}
if (ctx->parent.must_undo)
@@ -847,29 +850,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
ctx->flags.mode = TECO_MODE_PARSE_ONLY_COND;
return &teco_state_start;
- case '\'':
- if (ctx->flags.modifier_at ||
- (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) {
- teco_error_modifier_set(error, '\'');
- return NULL;
- }
- switch (ctx->flags.mode) {
- case TECO_MODE_PARSE_ONLY_COND:
- case TECO_MODE_PARSE_ONLY_COND_FORCE:
- if (!ctx->nest_level) {
- if (ctx->parent.must_undo)
- teco_undo_flags(ctx->flags);
- ctx->flags.mode = TECO_MODE_NORMAL;
- } else {
- if (ctx->parent.must_undo)
- teco_undo_gint(ctx->nest_level);
- ctx->nest_level--;
- }
- break;
- default:
- break;
- }
- return &teco_state_start;
+ case '\'': return teco_state_endcond(ctx, "'", error);
/*
* Word movement and deletion commands.
@@ -895,7 +876,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
*/
case '@':
if (ctx->flags.modifier_at) {
- teco_error_modifier_set(error, '@');
+ teco_error_modifier_set(error, "@");
return NULL;
}
/*
@@ -913,7 +894,7 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
if (ctx->flags.mode > TECO_MODE_NORMAL)
return &teco_state_start;
if (ctx->flags.modifier_colon >= 2) {
- teco_error_modifier_set(error, ':');
+ teco_error_modifier_set(error, ":");
return NULL;
}
if (ctx->parent.must_undo)
@@ -1096,6 +1077,10 @@ teco_state_fcommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error
['|'] = {&teco_state_start, teco_state_fcommand_cond_else}
};
+ switch (chr) {
+ case '"': return teco_state_endcond(ctx, "F\"", error);
+ }
+
return teco_machine_main_transition_input(ctx, transitions, G_N_ELEMENTS(transitions),
teco_ascii_toupper(chr), error);
}
@@ -1315,6 +1300,35 @@ TECO_DEFINE_STATE_COMMAND(teco_state_condcommand,
.input_cb = (teco_state_input_cb_t)teco_state_condcommand_input
);
+static teco_state_t *
+teco_state_endcond(teco_machine_main_t *ctx, const gchar *cmd, GError **error)
+{
+ if (ctx->flags.modifier_at ||
+ (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) {
+ teco_error_modifier_set(error, cmd);
+ return NULL;
+ }
+
+ switch (ctx->flags.mode) {
+ case TECO_MODE_PARSE_ONLY_COND:
+ case TECO_MODE_PARSE_ONLY_COND_FORCE:
+ if (!ctx->nest_level) {
+ if (ctx->parent.must_undo)
+ teco_undo_flags(ctx->flags);
+ ctx->flags.mode = TECO_MODE_NORMAL;
+ } else {
+ if (ctx->parent.must_undo)
+ teco_undo_gint(ctx->nest_level);
+ ctx->nest_level--;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return &teco_state_start;
+}
+
/*$ ^_ negate
* n^_ -> ~n -- Binary negation
*
diff --git a/src/error.h b/src/error.h
index 3d4334f..a848116 100644
--- a/src/error.h
+++ b/src/error.h
@@ -80,10 +80,10 @@ teco_error_syntax_set(GError **error, gunichar chr)
}
static inline void
-teco_error_modifier_set(GError **error, gchar chr)
+teco_error_modifier_set(GError **error, const gchar *cmd)
{
g_set_error(error, TECO_ERROR, TECO_ERROR_MODIFIER,
- "Unexpected modifier on <%c>", chr);
+ "Unexpected modifier on <%s>", cmd);
}
static inline void
diff --git a/src/parser.c b/src/parser.c
index c84881b..32e60cd 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -378,7 +378,8 @@ teco_machine_main_transition_input(teco_machine_main_t *ctx,
if ((ctx->flags.modifier_at && !transitions[chr].modifier_at) ||
(ctx->flags.mode == TECO_MODE_NORMAL &&
ctx->flags.modifier_colon > transitions[chr].modifier_colon)) {
- teco_error_modifier_set(error, chr);
+ gchar cmd[] = {chr, '\0'};
+ teco_error_modifier_set(error, cmd);
return NULL;
}
diff --git a/tests/testsuite.at b/tests/testsuite.at
index db2465f..0bd68d3 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -123,6 +123,11 @@ TE_CHECK([[1@O/foo,bar/ (0/0) !bar!]], 0, ignore, ignore)
TE_CHECK([[-1@O/foo/ 1@O/foo/ @O/,foo/]], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Conditionals])
+# FIXME: Add more test cases
+TE_CHECK([[0"N(0/0)F"]], 0, ignore, ignore)
+AT_CLEANUP
+
AT_SETUP([String arguments])
TE_CHECK([[Ifoo^Q]]TE_ESCAPE[[(0/0)]]TE_ESCAPE, 0, ignore, ignore)
TE_CHECK([[@I"foo^Q"(0/0)"]], 0, ignore, ignore)