aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorRobin Haberkorn <rhaberkorn@fmsbw.de>2025-12-26 18:10:42 +0100
committerRobin Haberkorn <rhaberkorn@fmsbw.de>2025-12-26 18:10:42 +0100
commitc2114fa0af73b42bc1ef302f7511ef87690cc0b1 (patch)
tree3a0ad484d1e4c06e20efa8358f4261f16abe7542 /src
parentd7330f252e6b0a1326eac6b5fc0b219a7b706eb7 (diff)
TECO_DEFINE_STATE() no longer constructs callback names for mandatory callbacks, but tries to use static assertionsHEADmaster
* Requiring state callbacks by generating their names (e.g. NAME##_input) has several disadvantages: * The callback is not explicitly referenced when the state is defined. So an unintroduced reader will see some static function, which is nowhere referenced and still doesn't cause "unused" warnings. * You cannot choose the name of function that implements the callback freely. * In "substates" you need to generate a callback function if you want to provide a default. You also need to provide dummy wrapper functions whenever you want to reuse some existing function as the implementation. * Instead, we are now using static assertions to check whether certain callbacks have been implemented. Unfortunately, this does not work on all compilers. In particular GCC won't consider references to state objects fully constant (even though they are) and does not allow them in _Static_assert (G_STATIC_ASSERT). This could only be made to work in newer GCC with -std=c2x or -std=gnu23 in combination with constexpr. It does work on Clang, though. So I introduced TECO_ASSERT_SAFE() which also passes if the expression is *not* constant. These static assertions are not crucial - they do not check anything that can differ between systems. So we can always rely on the checks performed by FreeBSD CI for instance. Also, you will of course quickly notice missing callbacks at runtime - with and without additional runtime assertions. * All mandatory callbacks must still be explicitly initialized in the TECO_DEFINE_STATE calls. * After getting rid of generated callback implementations, the TECO_DEFINE_STATE macros can finally be qualified with `static`. * The TECO_DECLARE_STATE() macro has been removed. It no longer abstracts anything and cannot be used to declare static teco_state_t anyway. Also TECO_DEFINE_UNDO_CALL() also doesn't have a DECLARE counterpart.
Diffstat (limited to 'src')
-rw-r--r--src/cmdline.c3
-rw-r--r--src/cmdline.h2
-rw-r--r--src/core-commands.c41
-rw-r--r--src/core-commands.h28
-rw-r--r--src/glob.c12
-rw-r--r--src/glob.h2
-rw-r--r--src/goto-commands.c28
-rw-r--r--src/goto-commands.h4
-rw-r--r--src/help.c3
-rw-r--r--src/help.h2
-rw-r--r--src/parser.c89
-rw-r--r--src/parser.h33
-rw-r--r--src/qreg-commands.c64
-rw-r--r--src/qreg-commands.h44
-rw-r--r--src/qreg.c34
-rw-r--r--src/ring.c11
-rw-r--r--src/ring.h6
-rw-r--r--src/sciteco.h10
-rw-r--r--src/search.c58
-rw-r--r--src/search.h14
-rw-r--r--src/spawn.c6
-rw-r--r--src/spawn.h4
-rw-r--r--src/stdio-commands.c9
-rw-r--r--src/stdio-commands.h4
-rw-r--r--src/symbols.c12
-rw-r--r--src/symbols.h2
26 files changed, 298 insertions, 227 deletions
diff --git a/src/cmdline.c b/src/cmdline.c
index e1a4628..d06b8c2 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -1504,5 +1504,6 @@ teco_state_save_cmdline_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg
* Q-Register <q>.
*/
TECO_DEFINE_STATE_EXPECTQREG(teco_state_save_cmdline,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_save_cmdline_got_register
);
diff --git a/src/cmdline.h b/src/cmdline.h
index 9123358..e8d69d5 100644
--- a/src/cmdline.h
+++ b/src/cmdline.h
@@ -120,4 +120,4 @@ void teco_cmdline_cleanup(void);
* Command states
*/
-TECO_DECLARE_STATE(teco_state_save_cmdline);
+extern teco_state_t teco_state_save_cmdline;
diff --git a/src/core-commands.c b/src/core-commands.c
index faf1c48..86a4b85 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -915,7 +915,9 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
teco_ascii_toupper(chr), error);
}
-TECO_DEFINE_STATE_START(teco_state_start);
+TECO_DEFINE_STATE_START(teco_state_start,
+ .input_cb = (teco_state_input_cb_t)teco_state_start_input
+);
/*$ "F<" ":F<"
* F< -- Go to loop start or jump to beginning of macro
@@ -1080,7 +1082,9 @@ teco_state_fcommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error
teco_ascii_toupper(chr), error);
}
-TECO_DEFINE_STATE_COMMAND(teco_state_fcommand);
+TECO_DEFINE_STATE_COMMAND(teco_state_fcommand,
+ .input_cb = (teco_state_input_cb_t)teco_state_fcommand_input
+);
static void
teco_undo_change_dir_action(gchar **dir, gboolean run)
@@ -1172,7 +1176,9 @@ teco_state_changedir_done(teco_machine_main_t *ctx, const teco_string_t *str, GE
* String-building characters are enabled on this
* command and directories can be tab-completed.
*/
-TECO_DEFINE_STATE_EXPECTDIR(teco_state_changedir);
+TECO_DEFINE_STATE_EXPECTDIR(teco_state_changedir,
+ .expectstring.done_cb = teco_state_changedir_done
+);
static teco_state_t *
teco_state_condcommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
@@ -1287,7 +1293,8 @@ teco_state_condcommand_input(teco_machine_main_t *ctx, gunichar chr, GError **er
}
TECO_DEFINE_STATE_COMMAND(teco_state_condcommand,
- .style = SCE_SCITECO_OPERATOR
+ .style = SCE_SCITECO_OPERATOR,
+ .input_cb = (teco_state_input_cb_t)teco_state_condcommand_input
);
/*$ ^_ negate
@@ -1701,7 +1708,9 @@ teco_state_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
teco_ascii_toupper(chr), error);
}
-TECO_DEFINE_STATE_COMMAND(teco_state_control);
+TECO_DEFINE_STATE_COMMAND(teco_state_control,
+ .input_cb = (teco_state_input_cb_t)teco_state_control_input
+);
static teco_state_t *
teco_state_ascii_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
@@ -1724,7 +1733,9 @@ teco_state_ascii_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
* Note that this command can be typed CTRL+Caret or
* Caret-Caret.
*/
-TECO_DEFINE_STATE(teco_state_ascii);
+TECO_DEFINE_STATE(teco_state_ascii,
+ .input_cb = (teco_state_input_cb_t)teco_state_ascii_input
+);
/*$ ^[^[ ^[$ $$ ^C terminate return
* [a1,a2,...]$$ -- Terminate command line or return from macro
@@ -1858,6 +1869,7 @@ teco_state_escape_end_of_macro(teco_machine_t *ctx, GError **error)
}
TECO_DEFINE_STATE_START(teco_state_escape,
+ .input_cb = (teco_state_input_cb_t)teco_state_escape_input,
.end_of_macro_cb = teco_state_escape_end_of_macro
);
@@ -1892,7 +1904,8 @@ teco_state_ctlc_initial(teco_machine_main_t *ctx, GError **error)
}
TECO_DEFINE_STATE_START(teco_state_ctlc,
- .initial_cb = (teco_state_initial_cb_t)teco_state_ctlc_initial
+ .initial_cb = (teco_state_initial_cb_t)teco_state_ctlc_initial,
+ .input_cb = (teco_state_input_cb_t)teco_state_ctlc_input
);
static teco_state_t *
@@ -1947,7 +1960,9 @@ teco_state_ctlc_control_input(teco_machine_main_t *ctx, gunichar chr, GError **e
* This state is necessary, so that you can type ^C^C exclusively with carets.
* Otherwise it would be very cumbersome to cause exits with ASCII characters only.
*/
-TECO_DEFINE_STATE_COMMAND(teco_state_ctlc_control);
+TECO_DEFINE_STATE_COMMAND(teco_state_ctlc_control,
+ .input_cb = (teco_state_input_cb_t)teco_state_ctlc_control_input
+);
/*$ ED flags
* flags ED -- Set and get ED-flags
@@ -2843,7 +2858,9 @@ teco_state_ecommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error
teco_ascii_toupper(chr), error);
}
-TECO_DEFINE_STATE_COMMAND(teco_state_ecommand);
+TECO_DEFINE_STATE_COMMAND(teco_state_ecommand,
+ .input_cb = (teco_state_input_cb_t)teco_state_ecommand_input
+);
gboolean
teco_state_insert_initial(teco_machine_main_t *ctx, GError **error)
@@ -2995,12 +3012,6 @@ teco_state_insert_indent_initial(teco_machine_main_t *ctx, GError **error)
return TRUE;
}
-static teco_state_t *
-teco_state_insert_indent_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
-{
- return teco_state_insert_done(ctx, str, error);
-}
-
/*
* Alternatives: ^i, ^I, <CTRL/I>, <TAB>
*/
diff --git a/src/core-commands.h b/src/core-commands.h
index 8f8966f..425379e 100644
--- a/src/core-commands.h
+++ b/src/core-commands.h
@@ -55,15 +55,15 @@ gboolean teco_state_command_process_edit_cmd(teco_machine_main_t *ctx, teco_mach
* FIXME: Most of these states can probably be private/static
* as they are only referenced from teco_state_start.
*/
-TECO_DECLARE_STATE(teco_state_fcommand);
+extern teco_state_t teco_state_fcommand;
void teco_undo_change_dir_to_current(void);
-TECO_DECLARE_STATE(teco_state_changedir);
+extern teco_state_t teco_state_changedir;
-TECO_DECLARE_STATE(teco_state_condcommand);
-TECO_DECLARE_STATE(teco_state_control);
-TECO_DECLARE_STATE(teco_state_ascii);
-TECO_DECLARE_STATE(teco_state_ecommand);
+extern teco_state_t teco_state_condcommand;
+extern teco_state_t teco_state_control;
+extern teco_state_t teco_state_ascii;
+extern teco_state_t teco_state_ecommand;
typedef struct {
teco_int_t from; /*< start position in glyphs */
@@ -88,18 +88,18 @@ gboolean teco_state_insert_process_edit_cmd(teco_machine_main_t *ctx, teco_machi
* @ingroup states
*
* @note Also serves as a base class of the replace-insertion commands.
- * @note You must always define a done_cb().
*/
#define TECO_DEFINE_STATE_INSERT(NAME, ...) \
TECO_DEFINE_STATE_EXPECTSTRING(NAME, \
.initial_cb = (teco_state_initial_cb_t)teco_state_insert_initial, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_insert_process_edit_cmd, \
.expectstring.process_cb = teco_state_insert_process, \
+ .expectstring.done_cb = teco_state_insert_done, \
##__VA_ARGS__ \
)
-TECO_DECLARE_STATE(teco_state_insert);
-TECO_DECLARE_STATE(teco_state_insert_indent);
+extern teco_state_t teco_state_insert;
+extern teco_state_t teco_state_insert_indent;
/**
* @class TECO_DEFINE_STATE_START
@@ -119,8 +119,8 @@ TECO_DECLARE_STATE(teco_state_insert_indent);
teco_state_t *teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error);
-TECO_DECLARE_STATE(teco_state_start);
-TECO_DECLARE_STATE(teco_state_control);
-TECO_DECLARE_STATE(teco_state_escape);
-TECO_DECLARE_STATE(teco_state_ctlc);
-TECO_DECLARE_STATE(teco_state_ctlc_control);
+extern teco_state_t teco_state_start;
+extern teco_state_t teco_state_control;
+extern teco_state_t teco_state_escape;
+extern teco_state_t teco_state_ctlc;
+extern teco_state_t teco_state_ctlc_control;
diff --git a/src/glob.c b/src/glob.c
index 9621f1a..d2bf713 100644
--- a/src/glob.c
+++ b/src/glob.c
@@ -38,10 +38,7 @@
#include "undo.h"
#include "glob.h"
-/*
- * FIXME: This state could be static.
- */
-TECO_DECLARE_STATE(teco_state_glob_filename);
+static teco_state_t teco_state_glob_filename;
/** @memberof teco_globber_t */
void
@@ -454,7 +451,8 @@ teco_state_glob_pattern_done(teco_machine_main_t *ctx, const teco_string_t *str,
* have to edit that register anyway.
*/
TECO_DEFINE_STATE_EXPECTGLOB(teco_state_glob_pattern,
- .expectstring.last = FALSE
+ .expectstring.last = FALSE,
+ .expectstring.done_cb = teco_state_glob_pattern_done
);
static teco_state_t *
@@ -593,4 +591,6 @@ teco_state_glob_filename_done(teco_machine_main_t *ctx, const teco_string_t *str
return &teco_state_start;
}
-TECO_DEFINE_STATE_EXPECTFILE(teco_state_glob_filename);
+static TECO_DEFINE_STATE_EXPECTFILE(teco_state_glob_filename,
+ .expectstring.done_cb = teco_state_glob_filename_done
+);
diff --git a/src/glob.h b/src/glob.h
index d11fbce..af52060 100644
--- a/src/glob.h
+++ b/src/glob.h
@@ -68,4 +68,4 @@ gboolean teco_state_expectglob_insert_completion(teco_machine_main_t *ctx, const
* Command states
*/
-TECO_DECLARE_STATE(teco_state_glob_pattern);
+extern teco_state_t teco_state_glob_pattern;
diff --git a/src/goto-commands.c b/src/goto-commands.c
index 05d495f..6fdaffc 100644
--- a/src/goto-commands.c
+++ b/src/goto-commands.c
@@ -35,8 +35,8 @@
#include "goto.h"
#include "goto-commands.h"
-TECO_DECLARE_STATE(teco_state_blockcomment);
-TECO_DECLARE_STATE(teco_state_eolcomment);
+static teco_state_t teco_state_blockcomment;
+static teco_state_t teco_state_eolcomment;
/**
* In TECO_MODE_PARSE_ONLY_GOTO mode, we remain in parse-only mode
@@ -113,7 +113,8 @@ teco_state_label_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
}
TECO_DEFINE_STATE(teco_state_label,
- .style = SCE_SCITECO_LABEL
+ .style = SCE_SCITECO_LABEL,
+ .input_cb = (teco_state_input_cb_t)teco_state_label_input
);
static teco_state_t *
@@ -221,7 +222,8 @@ gboolean teco_state_goto_insert_completion(teco_machine_main_t *ctx, const teco_
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_goto,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_goto_process_edit_cmd,
- .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_goto_insert_completion
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_goto_insert_completion,
+ .expectstring.done_cb = teco_state_goto_done
);
/**
@@ -242,28 +244,34 @@ TECO_DEFINE_STATE_EXPECTSTRING(teco_state_goto,
)
static teco_state_t *
-teco_state_blockcomment_star_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
+teco_state_blockcomment_star_input(teco_machine_t *ctx, gunichar chr, GError **error)
{
return chr == '!' ? &teco_state_start : &teco_state_blockcomment;
}
-TECO_DEFINE_STATE_COMMENT(teco_state_blockcomment_star);
+static TECO_DEFINE_STATE_COMMENT(teco_state_blockcomment_star,
+ .input_cb = teco_state_blockcomment_star_input
+);
static teco_state_t *
-teco_state_blockcomment_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
+teco_state_blockcomment_input(teco_machine_t *ctx, gunichar chr, GError **error)
{
return chr == '*' ? &teco_state_blockcomment_star : &teco_state_blockcomment;
}
-TECO_DEFINE_STATE_COMMENT(teco_state_blockcomment);
+static TECO_DEFINE_STATE_COMMENT(teco_state_blockcomment,
+ .input_cb = teco_state_blockcomment_input
+);
/*
* `!!` line comments are inspired by TECO-64.
*/
static teco_state_t *
-teco_state_eolcomment_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
+teco_state_eolcomment_input(teco_machine_t *ctx, gunichar chr, GError **error)
{
return chr == '\n' ? &teco_state_start : &teco_state_eolcomment;
}
-TECO_DEFINE_STATE_COMMENT(teco_state_eolcomment);
+static TECO_DEFINE_STATE_COMMENT(teco_state_eolcomment,
+ .input_cb = teco_state_eolcomment_input
+);
diff --git a/src/goto-commands.h b/src/goto-commands.h
index 45c68e9..ba60f93 100644
--- a/src/goto-commands.h
+++ b/src/goto-commands.h
@@ -24,5 +24,5 @@
extern teco_string_t teco_goto_skip_label;
extern gssize teco_goto_backup_pc;
-TECO_DECLARE_STATE(teco_state_label);
-TECO_DECLARE_STATE(teco_state_goto);
+extern teco_state_t teco_state_label;
+extern teco_state_t teco_state_goto;
diff --git a/src/help.c b/src/help.c
index 0bbbc54..74b9ecb 100644
--- a/src/help.c
+++ b/src/help.c
@@ -388,5 +388,6 @@ TECO_DEFINE_STATE_EXPECTSTRING(teco_state_help,
.initial_cb = (teco_state_initial_cb_t)teco_state_help_initial,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_help_process_edit_cmd,
.insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_help_insert_completion,
- .expectstring.string_building = FALSE
+ .expectstring.string_building = FALSE,
+ .expectstring.done_cb = teco_state_help_done
);
diff --git a/src/help.h b/src/help.h
index 3148e01..91a0368 100644
--- a/src/help.h
+++ b/src/help.h
@@ -27,4 +27,4 @@ gboolean teco_help_auto_complete(const gchar *topic_name, teco_string_t *insert)
* Command states
*/
-TECO_DECLARE_STATE(teco_state_help);
+extern teco_state_t teco_state_help;
diff --git a/src/parser.c b/src/parser.c
index a5e6e4f..0cf6031 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -476,27 +476,24 @@ teco_machine_stringbuilding_append_c(teco_machine_stringbuilding_t *ctx, teco_in
return TRUE;
}
-/*
- * FIXME: All teco_state_stringbuilding_* states could be static?
- */
static teco_state_t *teco_state_stringbuilding_ctl_input(teco_machine_stringbuilding_t *ctx,
gunichar chr, GError **error);
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctl);
+static teco_state_t teco_state_stringbuilding_ctl;
static teco_state_t *teco_state_stringbuilding_escaped_input(teco_machine_stringbuilding_t *ctx,
gunichar chr, GError **error);
-TECO_DECLARE_STATE(teco_state_stringbuilding_escaped);
+static teco_state_t teco_state_stringbuilding_escaped;
-TECO_DECLARE_STATE(teco_state_stringbuilding_lower);
-TECO_DECLARE_STATE(teco_state_stringbuilding_upper);
+static teco_state_t teco_state_stringbuilding_lower;
+static teco_state_t teco_state_stringbuilding_upper;
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctle);
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctle_num);
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctle_u);
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctle_code);
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctle_q);
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctle_quote);
-TECO_DECLARE_STATE(teco_state_stringbuilding_ctle_n);
+static teco_state_t teco_state_stringbuilding_ctle;
+static teco_state_t teco_state_stringbuilding_ctle_num;
+static teco_state_t teco_state_stringbuilding_ctle_u;
+static teco_state_t teco_state_stringbuilding_ctle_code;
+static teco_state_t teco_state_stringbuilding_ctle_q;
+static teco_state_t teco_state_stringbuilding_ctle_quote;
+static teco_state_t teco_state_stringbuilding_ctle_n;
static teco_state_t *
teco_state_stringbuilding_start_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -526,12 +523,13 @@ gboolean teco_state_stringbuilding_start_process_edit_cmd(teco_machine_stringbui
gunichar key, GError **error);
gboolean teco_state_stringbuilding_insert_completion(teco_machine_stringbuilding_t *ctx, const teco_string_t *str, GError **error);
-TECO_DEFINE_STATE(teco_state_stringbuilding_start,
- .is_start = TRUE,
- .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)
- teco_state_stringbuilding_start_process_edit_cmd,
- .insert_completion_cb = (teco_state_insert_completion_cb_t)
- teco_state_stringbuilding_insert_completion
+static TECO_DEFINE_STATE(teco_state_stringbuilding_start,
+ .is_start = TRUE,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_start_input,
+ .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)
+ teco_state_stringbuilding_start_process_edit_cmd,
+ .insert_completion_cb = (teco_state_insert_completion_cb_t)
+ teco_state_stringbuilding_insert_completion
);
static teco_state_t *
@@ -581,7 +579,9 @@ teco_state_stringbuilding_ctl_input(teco_machine_stringbuilding_t *ctx, gunichar
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_ctl);
+static TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_ctl,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctl_input,
+);
static teco_state_t *
teco_state_stringbuilding_escaped_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -613,7 +613,8 @@ teco_state_stringbuilding_escaped_input(teco_machine_stringbuilding_t *ctx, guni
gboolean teco_state_stringbuilding_escaped_process_edit_cmd(teco_machine_stringbuilding_t *ctx, teco_machine_t *parent_ctx,
gunichar key, GError **error);
-TECO_DEFINE_STATE(teco_state_stringbuilding_escaped,
+static TECO_DEFINE_STATE(teco_state_stringbuilding_escaped,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_escaped_input,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)
teco_state_stringbuilding_escaped_process_edit_cmd
);
@@ -639,7 +640,9 @@ teco_state_stringbuilding_lower_ctl_input(teco_machine_stringbuilding_t *ctx, gu
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_lower_ctl);
+static TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_lower_ctl,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_lower_ctl_input
+);
static teco_state_t *
teco_state_stringbuilding_lower_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -657,7 +660,9 @@ teco_state_stringbuilding_lower_input(teco_machine_stringbuilding_t *ctx, gunich
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE(teco_state_stringbuilding_lower);
+static TECO_DEFINE_STATE(teco_state_stringbuilding_lower,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_lower_input
+);
static teco_state_t *
teco_state_stringbuilding_upper_ctl_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -680,7 +685,9 @@ teco_state_stringbuilding_upper_ctl_input(teco_machine_stringbuilding_t *ctx, gu
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_upper_ctl);
+static TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_upper_ctl,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_upper_ctl_input
+);
static teco_state_t *
teco_state_stringbuilding_upper_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -698,7 +705,9 @@ teco_state_stringbuilding_upper_input(teco_machine_stringbuilding_t *ctx, gunich
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE(teco_state_stringbuilding_upper);
+static TECO_DEFINE_STATE(teco_state_stringbuilding_upper,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_upper_input
+);
static teco_state_t *
teco_state_stringbuilding_ctle_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -731,7 +740,9 @@ teco_state_stringbuilding_ctle_input(teco_machine_stringbuilding_t *ctx, gunicha
return next;
}
-TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_ctle);
+static TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_stringbuilding_ctle,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctle_input
+);
/* in cmdline.c */
gboolean teco_state_stringbuilding_qreg_process_edit_cmd(teco_machine_stringbuilding_t *ctx, teco_machine_t *parent_ctx,
@@ -782,7 +793,9 @@ teco_state_stringbuilding_ctle_num_input(teco_machine_stringbuilding_t *ctx, gun
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_num);
+static TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_num,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctle_num_input
+);
static teco_state_t *
teco_state_stringbuilding_ctle_u_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -817,7 +830,9 @@ teco_state_stringbuilding_ctle_u_input(teco_machine_stringbuilding_t *ctx, gunic
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_u);
+static TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_u,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctle_u_input
+);
static teco_state_t *
teco_state_stringbuilding_ctle_code_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -869,7 +884,9 @@ teco_state_stringbuilding_ctle_code_input(teco_machine_stringbuilding_t *ctx, gu
return &teco_state_stringbuilding_ctle_code;
}
-TECO_DEFINE_STATE(teco_state_stringbuilding_ctle_code);
+static TECO_DEFINE_STATE(teco_state_stringbuilding_ctle_code,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctle_code_input
+);
static teco_state_t *
teco_state_stringbuilding_ctle_q_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -897,7 +914,9 @@ teco_state_stringbuilding_ctle_q_input(teco_machine_stringbuilding_t *ctx, gunic
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_q);
+static TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_q,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctle_q_input
+);
static teco_state_t *
teco_state_stringbuilding_ctle_quote_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -940,7 +959,9 @@ teco_state_stringbuilding_ctle_quote_input(teco_machine_stringbuilding_t *ctx, g
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_quote);
+static TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_quote,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctle_quote_input
+);
static teco_state_t *
teco_state_stringbuilding_ctle_n_input(teco_machine_stringbuilding_t *ctx, gunichar chr, GError **error)
@@ -977,7 +998,9 @@ teco_state_stringbuilding_ctle_n_input(teco_machine_stringbuilding_t *ctx, gunic
return &teco_state_stringbuilding_start;
}
-TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_n);
+static TECO_DEFINE_STATE_STRINGBUILDING_QREG(teco_state_stringbuilding_ctle_n,
+ .input_cb = (teco_state_input_cb_t)teco_state_stringbuilding_ctle_n_input
+);
void
teco_machine_stringbuilding_init(teco_machine_stringbuilding_t *ctx, gunichar escape_char,
diff --git a/src/parser.h b/src/parser.h
index 2308925..4ab4d25 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -248,15 +248,18 @@ gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent
* @implements teco_state_t
* @ingroup states
*
- * @todo Should we eliminate required callbacks, this could be turned into a
- * struct initializer TECO_INIT_STATE() and TECO_DECLARE_STATE() would become pointless.
- * This would also ease declaring static states.
+ * Base class of all states.
+ *
+ * Since states are constant, you can append static assertions for required callbacks
+ * and other conditions.
+ * You should use TECO_ASSERT_SAFE(), but it won't be checked on all supported compilers.
+ * You should not put anything in front of the definition, though, so you
+ * can write `static TECO_DEFINE_STATE(...)`.
*/
#define TECO_DEFINE_STATE(NAME, ...) \
/** @ingroup states */ \
teco_state_t NAME = { \
.initial_cb = NULL, /* do nothing */ \
- .input_cb = (teco_state_input_cb_t)NAME##_input, /* always required */ \
.refresh_cb = NULL, /* do nothing */ \
.end_of_macro_cb = teco_state_end_of_macro, \
.process_edit_cmd_cb = teco_state_process_edit_cmd, \
@@ -265,11 +268,8 @@ gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent
.keymacro_mask = TECO_KEYMACRO_MASK_DEFAULT, \
.style = SCE_SCITECO_DEFAULT, \
##__VA_ARGS__ \
- }
-
-/** @ingroup states */
-#define TECO_DECLARE_STATE(NAME) \
- extern teco_state_t NAME
+ }; \
+ TECO_ASSERT_SAFE(NAME.input_cb != NULL)
/* in cmdline.c */
gboolean teco_state_caseinsensitive_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gunichar chr, GError **error);
@@ -610,18 +610,11 @@ gboolean teco_state_expectstring_insert_completion(teco_machine_main_t *ctx, con
* Super-class for states accepting string arguments
* Opaquely cares about alternative-escape characters,
* string building commands and accumulation into a string
- *
- * @note Generating the input_cb could be avoided if there were a default
- * implementation.
*/
#define TECO_DEFINE_STATE_EXPECTSTRING(NAME, ...) \
- static teco_state_t * \
- NAME##_input(teco_machine_main_t *ctx, gunichar chr, GError **error) \
- { \
- return teco_state_expectstring_input(ctx, chr, error); \
- } \
TECO_DEFINE_STATE(NAME, \
.initial_cb = (teco_state_initial_cb_t)teco_state_expectstring_initial, \
+ .input_cb = (teco_state_input_cb_t)teco_state_expectstring_input, \
.refresh_cb = (teco_state_refresh_cb_t)teco_state_expectstring_refresh, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \
teco_state_expectstring_process_edit_cmd, \
@@ -631,10 +624,10 @@ gboolean teco_state_expectstring_insert_completion(teco_machine_main_t *ctx, con
.style = SCE_SCITECO_STRING, \
.expectstring.string_building = TRUE, \
.expectstring.last = TRUE, \
- .expectstring.process_cb = NULL, /* do nothing */ \
- .expectstring.done_cb = NAME##_done, /* always required */ \
+ .expectstring.process_cb = NULL, /* do nothing */ \
##__VA_ARGS__ \
- )
+ ); \
+ TECO_ASSERT_SAFE(NAME.expectstring.done_cb != NULL)
gboolean teco_state_expectfile_process(teco_machine_main_t *ctx, const teco_string_t *str,
gsize new_chars, GError **error);
diff --git a/src/qreg-commands.c b/src/qreg-commands.c
index 83a45b1..5efb140 100644
--- a/src/qreg-commands.c
+++ b/src/qreg-commands.c
@@ -91,7 +91,9 @@ teco_state_pushqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
* Save Q-Register <q> contents on the global Q-Register push-down
* stack.
*/
-TECO_DEFINE_STATE_EXPECTQREG(teco_state_pushqreg);
+TECO_DEFINE_STATE_EXPECTQREG(teco_state_pushqreg,
+ .expectqreg.got_register_cb = teco_state_pushqreg_got_register
+);
static teco_state_t *
teco_state_popqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
@@ -128,7 +130,8 @@ teco_state_popqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
* Memory is reclaimed on command-line termination.
*/
TECO_DEFINE_STATE_EXPECTQREG(teco_state_popqreg,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_popqreg_got_register
);
static teco_state_t *
@@ -142,7 +145,8 @@ teco_state_eqcommand_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
}
TECO_DEFINE_STATE_EXPECTQREG(teco_state_eqcommand,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_eqcommand_got_register
);
static teco_state_t *
@@ -187,7 +191,9 @@ teco_state_loadqreg_done(teco_machine_main_t *ctx, const teco_string_t *str, GEr
* Undefined Q-Registers will be defined.
* The command fails if <file> could not be read.
*/
-TECO_DEFINE_STATE_EXPECTFILE(teco_state_loadqreg);
+TECO_DEFINE_STATE_EXPECTFILE(teco_state_loadqreg,
+ .expectstring.done_cb = teco_state_loadqreg_done
+);
static teco_state_t *
teco_state_epctcommand_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
@@ -199,7 +205,9 @@ teco_state_epctcommand_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
return &teco_state_saveqreg;
}
-TECO_DEFINE_STATE_EXPECTQREG(teco_state_epctcommand);
+TECO_DEFINE_STATE_EXPECTQREG(teco_state_epctcommand,
+ .expectqreg.got_register_cb = teco_state_epctcommand_got_register
+);
static teco_state_t *
teco_state_saveqreg_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
@@ -231,7 +239,9 @@ teco_state_saveqreg_done(teco_machine_main_t *ctx, const teco_string_t *str, GEr
* File names may also be tab-completed and string building
* characters are enabled by default.
*/
-TECO_DEFINE_STATE_EXPECTFILE(teco_state_saveqreg);
+TECO_DEFINE_STATE_EXPECTFILE(teco_state_saveqreg,
+ .expectstring.done_cb = teco_state_saveqreg_done
+);
static gboolean
teco_state_queryqreg_initial(teco_machine_main_t *ctx, GError **error)
@@ -346,7 +356,8 @@ teco_state_queryqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
* boolean.
*/
TECO_DEFINE_STATE_EXPECTQREG(teco_state_queryqreg,
- .initial_cb = (teco_state_initial_cb_t)teco_state_queryqreg_initial
+ .initial_cb = (teco_state_initial_cb_t)teco_state_queryqreg_initial,
+ .expectqreg.got_register_cb = teco_state_queryqreg_got_register
);
static teco_state_t *
@@ -360,7 +371,8 @@ teco_state_ctlucommand_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
}
TECO_DEFINE_STATE_EXPECTQREG(teco_state_ctlucommand,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_ctlucommand_got_register
);
static teco_state_t *
@@ -474,7 +486,8 @@ teco_state_setqregstring_nobuilding_done(teco_machine_main_t *ctx,
* is desired.
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_setqregstring_nobuilding,
- .expectstring.string_building = FALSE
+ .expectstring.string_building = FALSE,
+ .expectstring.done_cb = teco_state_setqregstring_nobuilding_done
);
static teco_state_t *
@@ -488,7 +501,8 @@ teco_state_eucommand_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
}
TECO_DEFINE_STATE_EXPECTQREG(teco_state_eucommand,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_eucommand_got_register
);
static gboolean
@@ -511,12 +525,6 @@ teco_state_setqregstring_building_initial(teco_machine_main_t *ctx, GError **err
return TRUE;
}
-static teco_state_t *
-teco_state_setqregstring_building_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
-{
- return teco_state_setqregstring_nobuilding_done(ctx, str, error);
-}
-
/*$ "EU" "EUq" ":EUq"
* [c1,c2,...]EUq[string]$ -- Set or append to Q-Register string with string building characters
* [c1,c2,...]:EUq[string]$
@@ -529,7 +537,8 @@ teco_state_setqregstring_building_done(teco_machine_main_t *ctx, const teco_stri
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_setqregstring_building,
.initial_cb = (teco_state_initial_cb_t)teco_state_setqregstring_building_initial,
- .expectstring.string_building = TRUE
+ .expectstring.string_building = TRUE,
+ .expectstring.done_cb = teco_state_setqregstring_nobuilding_done
);
static teco_state_t *
@@ -582,7 +591,9 @@ teco_state_getqregstring_got_register(teco_machine_main_t *ctx, teco_qreg_t *qre
*
* Specifying an undefined <q> yields an error.
*/
-TECO_DEFINE_STATE_EXPECTQREG(teco_state_getqregstring);
+TECO_DEFINE_STATE_EXPECTQREG(teco_state_getqregstring,
+ .expectqreg.got_register_cb = teco_state_getqregstring_got_register
+);
static teco_state_t *
teco_state_setqreginteger_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
@@ -631,7 +642,8 @@ teco_state_setqreginteger_got_register(teco_machine_main_t *ctx, teco_qreg_t *qr
* The register is defined if it does not exist.
*/
TECO_DEFINE_STATE_EXPECTQREG(teco_state_setqreginteger,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_setqreginteger_got_register
);
static teco_state_t *
@@ -665,7 +677,8 @@ teco_state_increaseqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg
* <q> will be defined if it does not exist.
*/
TECO_DEFINE_STATE_EXPECTQREG(teco_state_increaseqreg,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_increaseqreg_got_register
);
static teco_state_t *
@@ -724,7 +737,9 @@ teco_state_macro_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
* (as reported by \fBEE\fP), its contents must be and are checked to be in
* valid UTF-8.
*/
-TECO_DEFINE_STATE_EXPECTQREG(teco_state_macro);
+TECO_DEFINE_STATE_EXPECTQREG(teco_state_macro,
+ .expectqreg.got_register_cb = teco_state_macro_got_register
+);
static teco_state_t *
teco_state_indirect_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
@@ -762,7 +777,9 @@ teco_state_indirect_done(teco_machine_main_t *ctx, const teco_string_t *str, GEr
* As all \*(ST code, the contents of <file> must be in valid UTF-8
* even if operating in the \(lqdefault ANSI\(rq mode as configured by \fBED\fP.
*/
-TECO_DEFINE_STATE_EXPECTFILE(teco_state_indirect);
+TECO_DEFINE_STATE_EXPECTFILE(teco_state_indirect,
+ .expectstring.done_cb = teco_state_indirect_done
+);
static teco_state_t *
teco_state_copytoqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
@@ -865,5 +882,6 @@ teco_state_copytoqreg_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
* Register <q> will be created if it is undefined.
*/
TECO_DEFINE_STATE_EXPECTQREG(teco_state_copytoqreg,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_copytoqreg_got_register
);
diff --git a/src/qreg-commands.h b/src/qreg-commands.h
index e224797..d0f6990 100644
--- a/src/qreg-commands.h
+++ b/src/qreg-commands.h
@@ -51,48 +51,44 @@ gboolean teco_state_expectqreg_insert_completion(teco_machine_main_t *ctx, const
* Super class for states accepting Q-Register specifications.
*/
#define TECO_DEFINE_STATE_EXPECTQREG(NAME, ...) \
- static teco_state_t * \
- NAME##_input(teco_machine_main_t *ctx, gunichar chr, GError **error) \
- { \
- return teco_state_expectqreg_input(ctx, chr, error); \
- } \
TECO_DEFINE_STATE(NAME, \
.initial_cb = (teco_state_initial_cb_t)teco_state_expectqreg_initial, \
+ .input_cb = (teco_state_input_cb_t)teco_state_expectqreg_input, \
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \
teco_state_expectqreg_process_edit_cmd, \
.insert_completion_cb = (teco_state_insert_completion_cb_t) \
teco_state_expectqreg_insert_completion, \
.style = SCE_SCITECO_QREG, \
.expectqreg.type = TECO_QREG_REQUIRED, \
- .expectqreg.got_register_cb = NAME##_got_register, /* always required */ \
##__VA_ARGS__ \
- )
+ ); \
+ TECO_ASSERT_SAFE(NAME.expectqreg.got_register_cb != NULL)
/*
* FIXME: Some of these states are referenced only in qreg-commands.c,
* so they should be moved there?
*/
-TECO_DECLARE_STATE(teco_state_pushqreg);
-TECO_DECLARE_STATE(teco_state_popqreg);
+extern teco_state_t teco_state_pushqreg;
+extern teco_state_t teco_state_popqreg;
-TECO_DECLARE_STATE(teco_state_eqcommand);
-TECO_DECLARE_STATE(teco_state_loadqreg);
+extern teco_state_t teco_state_eqcommand;
+extern teco_state_t teco_state_loadqreg;
-TECO_DECLARE_STATE(teco_state_epctcommand);
-TECO_DECLARE_STATE(teco_state_saveqreg);
+extern teco_state_t teco_state_epctcommand;
+extern teco_state_t teco_state_saveqreg;
-TECO_DECLARE_STATE(teco_state_queryqreg);
+extern teco_state_t teco_state_queryqreg;
-TECO_DECLARE_STATE(teco_state_ctlucommand);
-TECO_DECLARE_STATE(teco_state_setqregstring_nobuilding);
-TECO_DECLARE_STATE(teco_state_eucommand);
-TECO_DECLARE_STATE(teco_state_setqregstring_building);
+extern teco_state_t teco_state_ctlucommand;
+extern teco_state_t teco_state_setqregstring_nobuilding;
+extern teco_state_t teco_state_eucommand;
+extern teco_state_t teco_state_setqregstring_building;
-TECO_DECLARE_STATE(teco_state_getqregstring);
-TECO_DECLARE_STATE(teco_state_setqreginteger);
-TECO_DECLARE_STATE(teco_state_increaseqreg);
+extern teco_state_t teco_state_getqregstring;
+extern teco_state_t teco_state_setqreginteger;
+extern teco_state_t teco_state_increaseqreg;
-TECO_DECLARE_STATE(teco_state_macro);
-TECO_DECLARE_STATE(teco_state_indirect);
+extern teco_state_t teco_state_macro;
+extern teco_state_t teco_state_indirect;
-TECO_DECLARE_STATE(teco_state_copytoqreg);
+extern teco_state_t teco_state_copytoqreg;
diff --git a/src/qreg.c b/src/qreg.c
index 8fca9e2..0ca463a 100644
--- a/src/qreg.c
+++ b/src/qreg.c
@@ -1377,15 +1377,12 @@ TECO_DEFINE_UNDO_SCALAR(teco_machine_qregspec_flags_t);
#define teco_undo_qregspec_flags(VAR) \
(*teco_undo_object_teco_machine_qregspec_flags_t_push(&(VAR)))
-/*
- * FIXME: All teco_state_qregspec_* states could be static?
- */
-TECO_DECLARE_STATE(teco_state_qregspec_start);
-TECO_DECLARE_STATE(teco_state_qregspec_start_global);
-TECO_DECLARE_STATE(teco_state_qregspec_caret);
-TECO_DECLARE_STATE(teco_state_qregspec_firstchar);
-TECO_DECLARE_STATE(teco_state_qregspec_secondchar);
-TECO_DECLARE_STATE(teco_state_qregspec_string);
+static teco_state_t teco_state_qregspec_start;
+static teco_state_t teco_state_qregspec_start_global;
+static teco_state_t teco_state_qregspec_caret;
+static teco_state_t teco_state_qregspec_firstchar;
+static teco_state_t teco_state_qregspec_secondchar;
+static teco_state_t teco_state_qregspec_string;
static teco_state_t *teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx,
gunichar chr, GError **error);
@@ -1445,8 +1442,9 @@ gboolean teco_state_qregspec_process_edit_cmd(teco_machine_qregspec_t *ctx, teco
gboolean teco_state_qregspec_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str,
GError **error);
-TECO_DEFINE_STATE(teco_state_qregspec_start,
+static TECO_DEFINE_STATE(teco_state_qregspec_start,
.is_start = TRUE,
+ .input_cb = (teco_state_input_cb_t)teco_state_qregspec_start_input,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd,
.insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_qregspec_insert_completion
);
@@ -1482,7 +1480,8 @@ teco_state_qregspec_start_global_input(teco_machine_qregspec_t *ctx, gunichar ch
* Alternatively, we'd have to introduce a teco_machine_qregspec_t::status attribute.
* Or even better, why not use special pointers like ((teco_state_t *)"teco_state_qregspec_done")?
*/
-TECO_DEFINE_STATE(teco_state_qregspec_start_global,
+static TECO_DEFINE_STATE(teco_state_qregspec_start_global,
+ .input_cb = (teco_state_input_cb_t)teco_state_qregspec_start_global_input,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd
);
@@ -1503,7 +1502,9 @@ teco_state_qregspec_caret_input(teco_machine_qregspec_t *ctx, gunichar chr, GErr
return teco_state_qregspec_done(ctx, error);
}
-TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_qregspec_caret);
+static TECO_DEFINE_STATE_CASEINSENSITIVE(teco_state_qregspec_caret,
+ .input_cb = (teco_state_input_cb_t)teco_state_qregspec_caret_input
+);
static teco_state_t *
teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gunichar chr, GError **error)
@@ -1519,7 +1520,8 @@ teco_state_qregspec_firstchar_input(teco_machine_qregspec_t *ctx, gunichar chr,
return &teco_state_qregspec_secondchar;
}
-TECO_DEFINE_STATE(teco_state_qregspec_firstchar,
+static TECO_DEFINE_STATE(teco_state_qregspec_firstchar,
+ .input_cb = (teco_state_input_cb_t)teco_state_qregspec_firstchar_input,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd
);
@@ -1537,7 +1539,8 @@ teco_state_qregspec_secondchar_input(teco_machine_qregspec_t *ctx, gunichar chr,
return teco_state_qregspec_done(ctx, error);
}
-TECO_DEFINE_STATE(teco_state_qregspec_secondchar,
+static TECO_DEFINE_STATE(teco_state_qregspec_secondchar,
+ .input_cb = (teco_state_input_cb_t)teco_state_qregspec_secondchar_input,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_process_edit_cmd
);
@@ -1587,7 +1590,8 @@ gboolean teco_state_qregspec_string_process_edit_cmd(teco_machine_qregspec_t *ct
gboolean teco_state_qregspec_string_insert_completion(teco_machine_qregspec_t *ctx, const teco_string_t *str,
GError **error);
-TECO_DEFINE_STATE(teco_state_qregspec_string,
+static TECO_DEFINE_STATE(teco_state_qregspec_string,
+ .input_cb = (teco_state_input_cb_t)teco_state_qregspec_string_input,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_qregspec_string_process_edit_cmd,
.insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_qregspec_string_insert_completion
);
diff --git a/src/ring.c b/src/ring.c
index 22db7ce..926ee72 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -639,7 +639,8 @@ teco_state_edit_file_done(teco_machine_main_t *ctx, const teco_string_t *str, GE
*/
TECO_DEFINE_STATE_EXPECTGLOB(teco_state_edit_file,
.initial_cb = (teco_state_initial_cb_t)teco_state_edit_file_initial,
- .expectstring.process_cb = teco_state_edit_file_process
+ .expectstring.process_cb = teco_state_edit_file_process,
+ .expectstring.done_cb = teco_state_edit_file_done
);
static teco_state_t *
@@ -714,7 +715,9 @@ teco_state_save_file_done(teco_machine_main_t *ctx, const teco_string_t *str, GE
* File names may also be tab-completed and string building
* characters are enabled by default.
*/
-TECO_DEFINE_STATE_EXPECTFILE(teco_state_save_file);
+TECO_DEFINE_STATE_EXPECTFILE(teco_state_save_file,
+ .expectstring.done_cb = teco_state_save_file_done
+);
static teco_state_t *
teco_state_read_file_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
@@ -748,7 +751,9 @@ teco_state_read_file_done(teco_machine_main_t *ctx, const teco_string_t *str, GE
/*
* NOTE: Video TECO allows glob patterns as an argument.
*/
-TECO_DEFINE_STATE_EXPECTFILE(teco_state_read_file);
+TECO_DEFINE_STATE_EXPECTFILE(teco_state_read_file,
+ .expectstring.done_cb = teco_state_read_file_done
+);
/*$ "EF" ":EF" close
* [n]EF -- Remove buffer from ring
diff --git a/src/ring.h b/src/ring.h
index e6b0658..8b8beaa 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -114,9 +114,9 @@ void teco_ring_cleanup(void);
* Command states
*/
-TECO_DECLARE_STATE(teco_state_edit_file);
-TECO_DECLARE_STATE(teco_state_save_file);
-TECO_DECLARE_STATE(teco_state_read_file);
+extern teco_state_t teco_state_edit_file;
+extern teco_state_t teco_state_save_file;
+extern teco_state_t teco_state_read_file;
void teco_state_ecommand_close(teco_machine_main_t *ctx, GError **error);
diff --git a/src/sciteco.h b/src/sciteco.h
index 388d6c4..2e6ced2 100644
--- a/src/sciteco.h
+++ b/src/sciteco.h
@@ -117,6 +117,16 @@ extern volatile sig_atomic_t teco_interrupted;
*/
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FILE, fclose);
+/**
+ * A "safe" compile-time assertion, which also passes if the expression is not constant.
+ *
+ * Can be useful since different compilers have different ideas about what's a constant expression.
+ * In particular GCC does not treat `static const` objects as constant (in the way it qualifies
+ * for _Static_assert()), while constexpr is only available since C23.
+ */
+#define TECO_ASSERT_SAFE(EXPR) \
+ G_STATIC_ASSERT(!__builtin_constant_p(EXPR) || (EXPR))
+
/*
* BEWARE DRAGONS!
*/
diff --git a/src/search.c b/src/search.c
index 83e22ef..2a39b59 100644
--- a/src/search.c
+++ b/src/search.c
@@ -882,7 +882,6 @@ teco_state_search_done(teco_machine_main_t *ctx, const teco_string_t *str, GErro
TECO_DEFINE_STATE_EXPECTSTRING(NAME, \
.initial_cb = (teco_state_initial_cb_t)teco_state_search_initial, \
.expectstring.process_cb = teco_state_search_process, \
- .expectstring.done_cb = NAME##_done, \
##__VA_ARGS__ \
)
@@ -956,7 +955,9 @@ teco_state_search_done(teco_machine_main_t *ctx, const teco_string_t *str, GErro
* Changing the <pattern> results in the search being reperformed
* from the beginning.
*/
-TECO_DEFINE_STATE_SEARCH(teco_state_search);
+TECO_DEFINE_STATE_SEARCH(teco_state_search,
+ .expectstring.done_cb = teco_state_search_done
+);
static gboolean
teco_state_search_all_initial(teco_machine_main_t *ctx, GError **error)
@@ -1074,7 +1075,8 @@ teco_state_search_all_done(teco_machine_main_t *ctx, const teco_string_t *str, G
* This is probably not very useful in practice, so it's not documented.
*/
TECO_DEFINE_STATE_SEARCH(teco_state_search_all,
- .initial_cb = (teco_state_initial_cb_t)teco_state_search_all_initial
+ .initial_cb = (teco_state_initial_cb_t)teco_state_search_all_initial,
+ .expectstring.done_cb = teco_state_search_all_done
);
static teco_state_t *
@@ -1157,7 +1159,9 @@ teco_state_search_kill_done(teco_machine_main_t *ctx, const teco_string_t *str,
/*
* ::FK is possible but doesn't make much sense, so it's undocumented.
*/
-TECO_DEFINE_STATE_SEARCH(teco_state_search_kill);
+TECO_DEFINE_STATE_SEARCH(teco_state_search_kill,
+ .expectstring.done_cb = teco_state_search_kill_done
+);
static teco_state_t *
teco_state_search_delete_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
@@ -1200,7 +1204,9 @@ teco_state_search_delete_done(teco_machine_main_t *ctx, const teco_string_t *str
* Searches for <pattern> just like the regular search command
* (\fBS\fP) but when found deletes the entire occurrence.
*/
-TECO_DEFINE_STATE_SEARCH(teco_state_search_delete);
+TECO_DEFINE_STATE_SEARCH(teco_state_search_delete,
+ .expectstring.done_cb = teco_state_search_delete_done
+);
static gboolean
teco_state_replace_insert_initial(teco_machine_main_t *ctx, GError **error)
@@ -1226,16 +1232,7 @@ teco_state_replace_insert_initial(teco_machine_main_t *ctx, GError **error)
return TRUE;
}
-static teco_state_t *
-teco_state_replace_insert_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
-{
- return teco_state_insert_done(ctx, str, error);
-}
-
-/*
- * FIXME: Could be static
- */
-TECO_DEFINE_STATE_INSERT(teco_state_replace_insert,
+static TECO_DEFINE_STATE_INSERT(teco_state_replace_insert,
.initial_cb = (teco_state_initial_cb_t)teco_state_replace_insert_initial
);
@@ -1245,10 +1242,9 @@ teco_state_replace_ignore_done(teco_machine_main_t *ctx, const teco_string_t *st
return &teco_state_start;
}
-/*
- * FIXME: Could be static
- */
-TECO_DEFINE_STATE_EXPECTSTRING(teco_state_replace_ignore);
+static TECO_DEFINE_STATE_EXPECTSTRING(teco_state_replace_ignore,
+ .expectstring.done_cb = teco_state_replace_ignore_done
+);
static teco_state_t *
teco_state_replace_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
@@ -1291,7 +1287,8 @@ teco_state_replace_done(teco_machine_main_t *ctx, const teco_string_t *str, GErr
* immediately and interactively.
*/
TECO_DEFINE_STATE_SEARCH(teco_state_replace,
- .expectstring.last = FALSE
+ .expectstring.last = FALSE,
+ .expectstring.done_cb = teco_state_replace_done
);
static teco_state_t *
@@ -1321,11 +1318,9 @@ teco_state_replace_default_insert_done(teco_machine_main_t *ctx, const teco_stri
return &teco_state_start;
}
-/*
- * FIXME: Could be static
- */
-TECO_DEFINE_STATE_INSERT(teco_state_replace_default_insert,
- .initial_cb = (teco_state_initial_cb_t)teco_state_replace_insert_initial
+static TECO_DEFINE_STATE_INSERT(teco_state_replace_default_insert,
+ .initial_cb = (teco_state_initial_cb_t)teco_state_replace_insert_initial,
+ .expectstring.done_cb = teco_state_replace_default_insert_done
);
static teco_state_t *
@@ -1346,10 +1341,9 @@ teco_state_replace_default_ignore_done(teco_machine_main_t *ctx, const teco_stri
return &teco_state_start;
}
-/*
- * FIXME: Could be static
- */
-TECO_DEFINE_STATE_EXPECTSTRING(teco_state_replace_default_ignore);
+static TECO_DEFINE_STATE_EXPECTSTRING(teco_state_replace_default_ignore,
+ .expectstring.done_cb = teco_state_replace_default_ignore_done
+);
static teco_state_t *
teco_state_replace_default_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
@@ -1391,7 +1385,8 @@ teco_state_replace_default_done(teco_machine_main_t *ctx, const teco_string_t *s
* register is implied instead.
*/
TECO_DEFINE_STATE_SEARCH(teco_state_replace_default,
- .expectstring.last = FALSE
+ .expectstring.last = FALSE,
+ .expectstring.done_cb = teco_state_replace_default_done
);
static teco_state_t *
@@ -1434,6 +1429,7 @@ teco_state_replace_default_all_done(teco_machine_main_t *ctx, const teco_string_
* <to>.
*/
TECO_DEFINE_STATE_SEARCH(teco_state_replace_default_all,
+ .initial_cb = (teco_state_initial_cb_t)teco_state_search_all_initial,
.expectstring.last = FALSE,
- .initial_cb = (teco_state_initial_cb_t)teco_state_search_all_initial
+ .expectstring.done_cb = teco_state_replace_default_all_done
);
diff --git a/src/search.h b/src/search.h
index 222ca6c..8c93f9c 100644
--- a/src/search.h
+++ b/src/search.h
@@ -22,10 +22,10 @@
void teco_state_control_search_mode(teco_machine_main_t *ctx, GError **error);
-TECO_DECLARE_STATE(teco_state_search);
-TECO_DECLARE_STATE(teco_state_search_all);
-TECO_DECLARE_STATE(teco_state_search_kill);
-TECO_DECLARE_STATE(teco_state_search_delete);
-TECO_DECLARE_STATE(teco_state_replace);
-TECO_DECLARE_STATE(teco_state_replace_default);
-TECO_DECLARE_STATE(teco_state_replace_default_all);
+extern teco_state_t teco_state_search;
+extern teco_state_t teco_state_search_all;
+extern teco_state_t teco_state_search_kill;
+extern teco_state_t teco_state_search_delete;
+extern teco_state_t teco_state_replace;
+extern teco_state_t teco_state_replace_default;
+extern teco_state_t teco_state_replace_default_all;
diff --git a/src/spawn.c b/src/spawn.c
index 73f389e..6745b4f 100644
--- a/src/spawn.c
+++ b/src/spawn.c
@@ -605,7 +605,8 @@ gboolean teco_state_execute_process_edit_cmd(teco_machine_main_t *ctx, teco_mach
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_execute,
.initial_cb = (teco_state_initial_cb_t)teco_state_execute_initial,
- .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_execute_process_edit_cmd
+ .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_execute_process_edit_cmd,
+ .expectstring.done_cb = teco_state_execute_done
);
static teco_state_t *
@@ -647,7 +648,8 @@ teco_state_egcommand_got_register(teco_machine_main_t *ctx, teco_qreg_t *qreg,
* The register <q> is defined if it does not already exist.
*/
TECO_DEFINE_STATE_EXPECTQREG(teco_state_egcommand,
- .expectqreg.type = TECO_QREG_OPTIONAL_INIT
+ .expectqreg.type = TECO_QREG_OPTIONAL_INIT,
+ .expectqreg.got_register_cb = teco_state_egcommand_got_register
);
/*
diff --git a/src/spawn.h b/src/spawn.h
index ef210e9..f1c087b 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -18,5 +18,5 @@
#include "parser.h"
-TECO_DECLARE_STATE(teco_state_execute);
-TECO_DECLARE_STATE(teco_state_egcommand);
+extern teco_state_t teco_state_execute;
+extern teco_state_t teco_state_egcommand;
diff --git a/src/stdio-commands.c b/src/stdio-commands.c
index 565f442..bd28049 100644
--- a/src/stdio-commands.c
+++ b/src/stdio-commands.c
@@ -118,7 +118,7 @@ teco_print(teco_machine_main_t *ctx, guint radix, GError **error)
* then octal and finally in hexadecimal.
* This won't happen e.g. in a loop that is closed on the command-line.
*/
-TECO_DECLARE_STATE(teco_state_print_octal);
+static teco_state_t teco_state_print_octal;
static gboolean
teco_state_print_decimal_initial(teco_machine_main_t *ctx, GError **error)
@@ -168,6 +168,7 @@ teco_state_print_decimal_end_of_macro(teco_machine_main_t *ctx, GError **error)
TECO_DEFINE_STATE_START(teco_state_print_decimal,
.initial_cb = (teco_state_initial_cb_t)teco_state_print_decimal_initial,
+ .input_cb = (teco_state_input_cb_t)teco_state_print_decimal_input,
.end_of_macro_cb = (teco_state_end_of_macro_cb_t)
teco_state_print_decimal_end_of_macro
);
@@ -224,8 +225,9 @@ teco_state_print_octal_end_of_macro(teco_machine_main_t *ctx, GError **error)
return TRUE;
}
-TECO_DEFINE_STATE_START(teco_state_print_octal,
+static TECO_DEFINE_STATE_START(teco_state_print_octal,
.initial_cb = (teco_state_initial_cb_t)teco_state_print_octal_initial,
+ .input_cb = (teco_state_input_cb_t)teco_state_print_octal_input,
.end_of_macro_cb = (teco_state_end_of_macro_cb_t)
teco_state_print_octal_end_of_macro
);
@@ -282,7 +284,8 @@ teco_state_print_string_done(teco_machine_main_t *ctx, const teco_string_t *str,
* ^EUq, ^E<...> and case folding.
*/
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_print_string,
- .initial_cb = (teco_state_initial_cb_t)teco_state_print_string_initial
+ .initial_cb = (teco_state_initial_cb_t)teco_state_print_string_initial,
+ .expectstring.done_cb = teco_state_print_string_done
);
/*$ T type typeout
diff --git a/src/stdio-commands.h b/src/stdio-commands.h
index 985d1ac..fd973dc 100644
--- a/src/stdio-commands.h
+++ b/src/stdio-commands.h
@@ -26,5 +26,5 @@ void teco_state_control_typeout(teco_machine_main_t *ctx, GError **error);
/*
* Command states
*/
-TECO_DECLARE_STATE(teco_state_print_decimal);
-TECO_DECLARE_STATE(teco_state_print_string);
+extern teco_state_t teco_state_print_decimal;
+extern teco_state_t teco_state_print_string;
diff --git a/src/symbols.c b/src/symbols.c
index 9cf1c35..caae09a 100644
--- a/src/symbols.c
+++ b/src/symbols.c
@@ -174,10 +174,7 @@ teco_scintilla_ssm(unsigned int iMessage, uptr_t wParam, sptr_t lParam)
iMessage, wParam, lParam);
}
-/*
- * FIXME: This state could be static.
- */
-TECO_DECLARE_STATE(teco_state_scintilla_lparam);
+static teco_state_t teco_state_scintilla_lparam;
static gboolean
teco_scintilla_parse_symbols(teco_machine_scintilla_t *scintilla, const teco_string_t *str, GError **error)
@@ -355,7 +352,8 @@ gboolean teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx
TECO_DEFINE_STATE_EXPECTSTRING(teco_state_scintilla_symbols,
.process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t)teco_state_scintilla_symbols_process_edit_cmd,
.insert_completion_cb = (teco_state_insert_completion_cb_t)teco_state_scintilla_symbols_insert_completion,
- .expectstring.last = FALSE
+ .expectstring.last = FALSE,
+ .expectstring.done_cb = teco_state_scintilla_symbols_done
);
#ifdef HAVE_LEXILLA
@@ -512,4 +510,6 @@ teco_state_scintilla_lparam_done(teco_machine_main_t *ctx, const teco_string_t *
return &teco_state_start;
}
-TECO_DEFINE_STATE_EXPECTSTRING(teco_state_scintilla_lparam);
+static TECO_DEFINE_STATE_EXPECTSTRING(teco_state_scintilla_lparam,
+ .expectstring.done_cb = teco_state_scintilla_lparam_done
+);
diff --git a/src/symbols.h b/src/symbols.h
index 1d0af12..885479d 100644
--- a/src/symbols.h
+++ b/src/symbols.h
@@ -61,4 +61,4 @@ extern teco_symbol_list_t teco_symbol_list_scilexer;
* Command states
*/
-TECO_DECLARE_STATE(teco_state_scintilla_symbols);
+extern teco_state_t teco_state_scintilla_symbols;