aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/parser.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.h')
-rw-r--r--src/parser.h100
1 files changed, 63 insertions, 37 deletions
diff --git a/src/parser.h b/src/parser.h
index 05a9715..066896f 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2023 Robin Haberkorn
+ * Copyright (C) 2012-2024 Robin Haberkorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,6 +16,8 @@
*/
#pragma once
+#include <stdbool.h>
+
#include <glib.h>
#include <Scintilla.h>
@@ -23,6 +25,7 @@
#include "sciteco.h"
#include "string-utils.h"
#include "goto.h"
+#include "undo.h"
#include "qreg.h"
/*
@@ -36,7 +39,9 @@ typedef struct {
/** how many iterations are left */
teco_int_t counter;
/** Program counter of loop start command */
- guint pc : sizeof(guint)*8 - 1;
+ gsize pc;
+ /** Brace level at loop start */
+ guint brace_level : sizeof(guint)*8 - 1;
/**
* Whether the loop represents an argument
* barrier or not (it "passes through"
@@ -46,7 +51,7 @@ typedef struct {
* a signed integer, it's ok steal one
* bit for the pass_through flag.
*/
- gboolean pass_through : 1;
+ bool pass_through : 1;
} teco_loop_context_t;
extern GArray *teco_loop_stack;
@@ -71,8 +76,8 @@ void undo__remove_index__teco_loop_stack(guint);
* FIXME: Maybe use TECO_DECLARE_VTABLE_METHOD()?
*/
typedef const struct {
- gboolean string_building : 1;
- gboolean last : 1;
+ bool string_building : 1;
+ bool last : 1;
/**
* Called repeatedly to process chunks of input and give interactive feedback.
@@ -99,17 +104,18 @@ typedef const struct {
} teco_state_expectqreg_t;
typedef gboolean (*teco_state_initial_cb_t)(teco_machine_t *ctx, GError **error);
-typedef teco_state_t *(*teco_state_input_cb_t)(teco_machine_t *ctx, gchar chr, GError **error);
+typedef teco_state_t *(*teco_state_input_cb_t)(teco_machine_t *ctx, gunichar chr, GError **error);
typedef gboolean (*teco_state_refresh_cb_t)(teco_machine_t *ctx, GError **error);
typedef gboolean (*teco_state_end_of_macro_cb_t)(teco_machine_t *ctx, GError **error);
typedef gboolean (*teco_state_process_edit_cmd_cb_t)(teco_machine_t *ctx, teco_machine_t *parent_ctx,
- gchar key, GError **error);
+ gunichar key, GError **error);
typedef enum {
- TECO_FNMACRO_MASK_START = (1 << 0),
- TECO_FNMACRO_MASK_STRING = (1 << 1),
- TECO_FNMACRO_MASK_DEFAULT = ~((1 << 2)-1)
-} teco_fnmacro_mask_t;
+ TECO_KEYMACRO_MASK_START = (1 << 0),
+ TECO_KEYMACRO_MASK_STRING = (1 << 1),
+ TECO_KEYMACRO_MASK_CASEINSENSITIVE = (1 << 2),
+ TECO_KEYMACRO_MASK_DEFAULT = ~((1 << 3)-1)
+} teco_keymacro_mask_t;
/**
* A teco_machine_t state.
@@ -182,19 +188,19 @@ struct teco_state_t {
/**
* Whether this state is a start state (ie. not within any
* escape sequence etc.).
- * This is separate of TECO_FNMACRO_MASK_START which is set
+ * This is separate of TECO_KEYMACRO_MASK_START which is set
* only in the main machine's start states.
*/
- gboolean is_start : 1;
+ bool is_start : 1;
/**
- * Function key macro mask.
+ * Key macro mask.
* This is not a bitmask since it is compared with values set
* from TECO, so the bitorder needs to be defined.
*
* @fixme If we intend to "forward" masks from other state machines like
* teco_machine_stringbuilding_t, this should probably be a callback.
*/
- teco_fnmacro_mask_t fnmacro_mask : 8;
+ teco_keymacro_mask_t keymacro_mask : 8;
/**
* Additional state-dependent callbacks and settings.
@@ -214,7 +220,7 @@ struct teco_state_t {
gboolean teco_state_end_of_macro(teco_machine_t *ctx, GError **error);
/* in cmdline.c */
-gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gchar chr, GError **error);
+gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gunichar chr, GError **error);
/**
* @interface TECO_DEFINE_STATE
@@ -234,7 +240,7 @@ gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent
.end_of_macro_cb = teco_state_end_of_macro, \
.process_edit_cmd_cb = teco_state_process_edit_cmd, \
.is_start = FALSE, \
- .fnmacro_mask = TECO_FNMACRO_MASK_DEFAULT, \
+ .keymacro_mask = TECO_KEYMACRO_MASK_DEFAULT, \
##__VA_ARGS__ \
}
@@ -243,20 +249,21 @@ gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent
extern teco_state_t NAME
/* in cmdline.c */
-gboolean teco_state_caseinsensitive_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gchar chr, GError **error);
+gboolean teco_state_caseinsensitive_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gunichar chr, GError **error);
/**
* @interface TECO_DEFINE_STATE_CASEINSENSITIVE
* @implements TECO_DEFINE_STATE
* @ingroup states
*
- * Base class of states with case-insenstive input.
+ * Base class of states with case-insensitive input.
*
* This is meant for states accepting command characters
* that can possibly be case-folded.
*/
#define TECO_DEFINE_STATE_CASEINSENSITIVE(NAME, ...) \
TECO_DEFINE_STATE(NAME, \
+ .keymacro_mask = TECO_KEYMACRO_MASK_CASEINSENSITIVE, \
.process_edit_cmd_cb = teco_state_caseinsensitive_process_edit_cmd, \
##__VA_ARGS__ \
)
@@ -278,6 +285,8 @@ struct teco_machine_t {
* Whether side effects must be reverted on rubout.
* State machines created within macro calls don't have to
* even in interactive mode.
+ * In fact you MUST not revert side effects if this is FALSE
+ * as the data no longer exists on the call stack at undo-time.
*/
gboolean must_undo;
};
@@ -296,7 +305,7 @@ teco_machine_reset(teco_machine_t *ctx, teco_state_t *initial)
teco_undo_ptr(ctx->current) = initial;
}
-gboolean teco_machine_input(teco_machine_t *ctx, gchar chr, GError **error);
+gboolean teco_machine_input(teco_machine_t *ctx, gunichar chr, GError **error);
typedef enum {
TECO_STRINGBUILDING_MODE_NORMAL = 0,
@@ -307,9 +316,6 @@ typedef enum {
/**
* A stringbuilding state machine.
*
- * @fixme Should contain the escape char (currently in teco_machine_expectstring_t),
- * so that we can escape it via ^Q.
- *
* @extends teco_machine_t
*/
typedef struct teco_machine_stringbuilding_t {
@@ -327,7 +333,7 @@ typedef struct teco_machine_stringbuilding_t {
* If this is `[` or `{`, it is assumed that `]` and `}` must
* be escaped as well by teco_machine_stringbuilding_escape().
*/
- gchar escape_char;
+ gunichar escape_char;
/**
* Q-Register table for local registers.
@@ -348,11 +354,28 @@ typedef struct teco_machine_stringbuilding_t {
* (see teco_state_stringbuilding_start_process_edit_cmd()).
*/
teco_string_t *result;
+
+ /**
+ * Encoding of string in `result`.
+ * This is inherited from the embedding command and may depend on
+ * the buffer's or Q-Register's encoding.
+ */
+ guint codepage;
} teco_machine_stringbuilding_t;
-void teco_machine_stringbuilding_init(teco_machine_stringbuilding_t *ctx, gchar escape_char,
+void teco_machine_stringbuilding_init(teco_machine_stringbuilding_t *ctx, gunichar escape_char,
teco_qreg_table_t *locals, gboolean must_undo);
+static inline void
+teco_machine_stringbuilding_set_codepage(teco_machine_stringbuilding_t *ctx,
+ guint codepage)
+{
+ /* NOTE: This is not safe to undo in macro calls. */
+ if (ctx->parent.must_undo)
+ teco_undo_guint(ctx->codepage);
+ ctx->codepage = codepage;
+}
+
void teco_machine_stringbuilding_reset(teco_machine_stringbuilding_t *ctx);
/**
@@ -365,7 +388,7 @@ void teco_machine_stringbuilding_reset(teco_machine_stringbuilding_t *ctx);
* @return FALSE in case of error.
*/
static inline gboolean
-teco_machine_stringbuilding_input(teco_machine_stringbuilding_t *ctx, gchar chr,
+teco_machine_stringbuilding_input(teco_machine_stringbuilding_t *ctx, gunichar chr,
teco_string_t *result, GError **error)
{
ctx->result = result;
@@ -424,7 +447,8 @@ typedef enum {
struct teco_machine_main_t {
teco_machine_t parent;
- gint macro_pc;
+ /* signed because it is sometimes set to -1 for flow control */
+ gssize macro_pc;
/**
* Aliases bitfield with an integer.
@@ -435,8 +459,8 @@ struct teco_machine_main_t {
struct {
teco_mode_t mode : 8;
- gboolean modifier_colon : 1;
- gboolean modifier_at : 1;
+ bool modifier_colon : 1;
+ bool modifier_at : 1;
};
guint __flags;
};
@@ -481,7 +505,7 @@ void teco_machine_main_init(teco_machine_main_t *ctx,
gboolean teco_machine_main_eval_colon(teco_machine_main_t *ctx);
gboolean teco_machine_main_step(teco_machine_main_t *ctx,
- const gchar *macro, gint stop_pos, GError **error);
+ const gchar *macro, gsize stop_pos, GError **error);
gboolean teco_execute_macro(const gchar *macro, gsize macro_len,
teco_qreg_table_t *qreg_table_locals, GError **error);
@@ -500,17 +524,18 @@ typedef const struct {
*/
teco_state_t *teco_machine_main_transition_input(teco_machine_main_t *ctx,
teco_machine_main_transition_t *transitions,
- guint len, gchar chr, GError **error);
+ guint len, gunichar chr, GError **error);
void teco_machine_main_clear(teco_machine_main_t *ctx);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(teco_machine_main_t, teco_machine_main_clear);
-teco_state_t *teco_state_expectstring_input(teco_machine_main_t *ctx, gchar chr, GError **error);
+gboolean teco_state_expectstring_initial(teco_machine_main_t *ctx, GError **error);
+teco_state_t *teco_state_expectstring_input(teco_machine_main_t *ctx, gunichar chr, GError **error);
gboolean teco_state_expectstring_refresh(teco_machine_main_t *ctx, GError **error);
/* in cmdline.c */
-gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gchar key, GError **error);
+gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTSTRING
@@ -526,15 +551,16 @@ gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco
*/
#define TECO_DEFINE_STATE_EXPECTSTRING(NAME, ...) \
static teco_state_t * \
- NAME##_input(teco_machine_main_t *ctx, gchar chr, GError **error) \
+ 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, \
.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, \
- .fnmacro_mask = TECO_FNMACRO_MASK_STRING, \
+ .keymacro_mask = TECO_KEYMACRO_MASK_STRING, \
.expectstring.string_building = TRUE, \
.expectstring.last = TRUE, \
.expectstring.process_cb = NULL, /* do nothing */ \
@@ -546,7 +572,7 @@ gboolean teco_state_expectfile_process(teco_machine_main_t *ctx, const teco_stri
gsize new_chars, GError **error);
/* in cmdline.c */
-gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gchar key, GError **error);
+gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTFILE
@@ -562,7 +588,7 @@ gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_m
)
/* in cmdline.c */
-gboolean teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gchar key, GError **error);
+gboolean teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error);
/**
* @interface TECO_DEFINE_STATE_EXPECTDIR