From 9e101ec36e0bf45f294f63015e0352d1d08d641d Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 23 Mar 2025 18:31:09 +0300 Subject: the ES command (send Scintilla message) now supports passing both wParam and lParam as null-terminated strings * Being able to embed null bytes into the lParam string is practically useless - there aren't any messages where this is useful and where there are no native SciTECO counterparts - so this case is now catched and the null-byte separates wParam from lParam. * wParam can be the empty string, but it is not supported to pass wParam as a string and lParam as the empty string. If the second string argument ends in ^@, lParam is popped from the stack instead. * This is a temporary workaround until we can properly parse the Scintilla.iface and generate more elegant per-message wrappers. * It in particular unlocks the SCI_SETREPRESENTATION and SCI_SETPROPERTY messages. The former allows us to write a special hex-editor macro which sets hexadecimal character representations, while the latter allows you to set lexer properties. * The C-based lexers ("cpp" in Lexilla) can now take preprocessor definitions into account. This is disabled by default, unless you set lexer.c.defines before opening a file. You can also set it interactively and re-set the lexer. For instance: ^U[lexer.c.defines]NDEBUG$ M[lexer.set.c] --- src/symbols.c | 56 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'src/symbols.c') diff --git a/src/symbols.c b/src/symbols.c index 32a33da..66edd90 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -243,11 +243,6 @@ teco_state_scintilla_symbols_done(teco_machine_main_t *ctx, const teco_string_t return NULL; ctx->scintilla.iMessage = value; } - if (!ctx->scintilla.wParam) { - if (!teco_expressions_pop_num_calc(&value, 0, error)) - return NULL; - ctx->scintilla.wParam = value; - } return &teco_state_scintilla_lparam; } @@ -259,8 +254,11 @@ gboolean teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx GError **error); /*$ ES scintilla message - * -- Send Scintilla message - * [lParam,][wParam,][message]ES[message][,wParam]$[lParam]$ -> result + * [lParam,][wParam,][message]ES$ -> result -- Send Scintilla message + * [lParam,][wParam]ES[message]$$ -> result + * [lParam]ES[message][,wParam]$$ -> result + * [wParam]ES[message]$[lParam]$ -> result + * [lParam]ES[message]$[wParam]^@[lParam]$ -> result * * Send Scintilla message with code specified by * , and . @@ -273,9 +271,15 @@ gboolean teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx * It is automatically null-terminated. * If the second string argument is empty, is popped * from the stack instead. + * If the second string argument contains a null-byte (\fB^@\fP), + * both and are passed as null-terminated + * string pointers to Scintilla. + * If the second string ends in a null-byte, is still + * popped from the stack. * Parameters popped from the stack may be omitted, in which * case 0 is implied. - * The message's return value is pushed onto the stack. + * The message's return value is always pushed onto the stack + * (0 if the message has no documented return values). * * All messages defined by Scintilla (as C macros in Scintilla.h) * can be used by passing their name as a string to ES @@ -283,7 +287,8 @@ gboolean teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx * The \(lqSCI_\(rq prefix may be omitted and message symbols * are case-insensitive. * Only the Lexilla style names (SCE_...) - * may be used symbolically with the ES command as . + * may be used symbolically with the ES command as in + * the first string argument. * In interactive mode, symbols may be auto-completed by * pressing Tab. * String-building characters are by default interpreted @@ -299,7 +304,7 @@ gboolean teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx * (shared library or DLL) is expected, * that implements the Lexilla protocol. * The \(lq.so\(rq or \(lq.dll\(rq extension is optional. - * The concrete lexer name is the remaining of the string after + * The concrete lexer name is the remainder of the string after * the null-byte. * This allows you to use lexers from external lexer libraries * like Scintillua. @@ -318,6 +323,8 @@ gboolean teco_state_scintilla_symbols_insert_completion(teco_machine_main_t *ctx * .BR Warning : * Almost all Scintilla messages may be dispatched using * this command. + * If called wrongly, you can easily crash the editor. + * Therefore it is not recommended to invoke ES interactively. * \*(ST does not keep track of the editor state changes * performed by these commands and cannot undo them. * You should never use it to change the editor state @@ -458,12 +465,31 @@ teco_state_scintilla_lparam_done(teco_machine_main_t *ctx, const teco_string_t * return NULL; } else if (str->len > 0) { /* - * NOTE: There may even be messages that read strings - * with embedded nulls. + * Theoretically, Scintilla could use null bytes from the string specified. + * This could only be the case for messages where the string length is + * passed in wParam. In practice however, there are no such messages, + * we would possible want to call. + * Therefore we pass the first null-terminated string as wParam, + * which unlocks useful messages like + * SCI_SETREPRESENTATIONS and SCI_SETPROPERTY. */ - lParam = (sptr_t)str->data; - } else { - teco_int_t v; + const gchar *p = memchr(str->data, '\0', str->len); + if (p) { + ctx->scintilla.wParam = (uptr_t)str->data; + if (str->len > p - str->data + 1) + lParam = (sptr_t)(p+1); + } else { + lParam = (sptr_t)str->data; + } + } + + teco_int_t v; + if (!ctx->scintilla.wParam) { + if (!teco_expressions_pop_num_calc(&v, 0, error)) + return NULL; + ctx->scintilla.wParam = v; + } + if (!lParam) { if (!teco_expressions_pop_num_calc(&v, 0, error)) return NULL; lParam = v; -- cgit v1.2.3