diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2024-12-21 20:57:40 +0300 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2024-12-22 19:33:48 +0300 |
commit | c174f9be70855e89f606547cfa5471942d238038 (patch) | |
tree | f7e000c4168b8b9ac1ab76330b09c87a6e845955 | |
parent | 157f4235a0cb2d6a37b131e0c52fecef9566f32c (diff) | |
download | sciteco-c174f9be70855e89f606547cfa5471942d238038.tar.gz |
support external Scintilla lexer libraries and Scintillua in particular
* @ES/SCI_SETILEXER/lib^@name/ now opens the lexer <name> in library <lib>.
* You need to define the environment variable $SCITECO_SCINTILLUA_LEXERS to point
to the lexers/ subdirectory (containing the *.lua files).
Perhaps this should default to the dirname of <lib>?
* The semantics of SCI_NAMEOFSTYLE have been changed:
It now returns style ids when given style names, so you can actually write
Scintillua lexer *.tes files.
This will be superfluous if we had a way to return strings from Scintilla messages into
Q-Registers, e.g. 23@EPq/SCI_NAMEOFSTYLE/.
* We now depend on gmodule as well, but it should always be part of glib.
It does not change the library dependencies of any package.
It might result in gmodule shared libraries to be bundled in the Win32 and Mac OS
packages if they weren't already.
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | doc/sciteco.1.in | 6 | ||||
-rw-r--r-- | doc/sciteco.7.template | 11 | ||||
-rw-r--r-- | src/error.h | 9 | ||||
-rw-r--r-- | src/symbols.c | 108 |
5 files changed, 124 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac index 72fc56d..41c0a05 100644 --- a/configure.ac +++ b/configure.ac @@ -126,7 +126,7 @@ AC_SUBST(DOXYGEN_HAVE_DOT) AC_CHECK_PROG(SCITECO, sciteco, sciteco) # Checks for libraries. -PKG_CHECK_MODULES(LIBGLIB, [glib-2.0 >= 2.44], [ +PKG_CHECK_MODULES(LIBGLIB, [glib-2.0 >= 2.44 gmodule-2.0], [ CFLAGS="$CFLAGS $LIBGLIB_CFLAGS" CXXFLAGS="$CXXFLAGS $LIBGLIB_CFLAGS" LIBS="$LIBS $LIBGLIB_LIBS" diff --git a/doc/sciteco.1.in b/doc/sciteco.1.in index 82c1a47..2b3d3bf 100644 --- a/doc/sciteco.1.in +++ b/doc/sciteco.1.in @@ -289,6 +289,12 @@ on Windows. On all other platforms (including UNIX/Linux) this variable defaults to the standard library installation path at .BR "@scitecolibdir@" . +.TP +.SCITECO_TOPIC "$SCITECO_SCINTILLUA_LEXERS" +.B SCITECO_SCINTILLUA_LEXERS +The Scintillua \(lqlexers/\(rq directory. +This is passed as the \(lqscintillua.lexers\(rq library property when +loading a Scintillua lexer via the \fBSCI_SETILEXER\fP Scintilla message. . .LP The \fBHOME\fP, \fBSCITECOCONFIG\fP and \fBSCITECOPATH\fP environment diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template index 8c049ee..053a5cb 100644 --- a/doc/sciteco.7.template +++ b/doc/sciteco.7.template @@ -2383,9 +2383,14 @@ Scintilla messages and other documentation: Scintilla .UE .TP -Scinterm manual, documenting the mapping of \(lqRGB\(rq values to terminal colors on curses user interfaces: -.UR http://foicica.com/scinterm/manual.html -Scinterm manual +Scinterm website, documenting the mapping of \(lqRGB\(rq values to terminal colors on curses user interfaces: +.UR https://orbitalquark.github.io/scinterm/ +Scinterm website +.UE +.TP +Scintillua manual, detailing usage of Lua-based Scintilla lexers: +.UR https://orbitalquark.github.io/scintillua/manual.html +Scintillua manual .UE .TP Suitable terminal fonts for icon support in Curses (see \fBED\fP flags): diff --git a/src/error.h b/src/error.h index c51f528..021f759 100644 --- a/src/error.h +++ b/src/error.h @@ -17,6 +17,7 @@ #pragma once #include <glib.h> +#include <gmodule.h> #include "sciteco.h" #include "string-utils.h" @@ -53,6 +54,7 @@ typedef enum { TECO_ERROR_MEMLIMIT, TECO_ERROR_CLIPBOARD, TECO_ERROR_WIN32, + TECO_ERROR_MODULE, /** Interrupt current operation */ TECO_ERROR_INTERRUPTED, @@ -165,6 +167,13 @@ teco_error_win32_set(GError **error, const gchar *prefix, gint err) #endif static inline void +teco_error_module_set(GError **error, const gchar *prefix) +{ + g_set_error(error, TECO_ERROR, TECO_ERROR_MODULE, "%s: %s", + prefix, g_module_error()); +} + +static inline void teco_error_interrupted_set(GError **error) { g_set_error_literal(error, TECO_ERROR, TECO_ERROR_INTERRUPTED, "Interrupted"); diff --git a/src/symbols.c b/src/symbols.c index 944d01d..7198639 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -23,6 +23,7 @@ #include <string.h> #include <glib.h> +#include <gmodule.h> #include <Scintilla.h> #ifdef HAVE_LEXILLA @@ -288,6 +289,27 @@ gboolean teco_state_scintilla_symbols_process_edit_cmd(teco_machine_main_t *ctx, * Lexilla lexer name as a string argument for the \fBSCI_SETILEXER\fP * message, i.e. in order to load a Lexilla lexer * (this works similar to the old \fBSCI_SETLEXERLANGUAGE\fP message). + * If the lexer name contains a null-byte, the second string + * argument is split into two: + * Up until the null-byte, the path of an external lexer library + * (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 null-byte. + * This allows you to use lexers from external lexer libraries + * like Scintillua. + * When detecting Scintillua, \*(ST will automatically pass down + * the \fBSCITECO_SCINTILLUA_LEXERS\fP environment variable as + * the \(lqscintillua.lexers\(rq library property for specifying + * the location of Scintillua's Lua lexer files. + * + * In order to facilitate the use of Scintillua lexers, the semantics + * of \fBSCI_NAMEOFSTYLE\fP have also been changed. + * Instead of returning the name for a given style id, it now + * returns the style id when given the name of a style in the + * second string argument of \fBES\fP, i.e. it allows you + * to look up style ids by name. * * .BR Warning : * Almost all Scintilla messages may be dispatched using @@ -321,24 +343,94 @@ teco_state_scintilla_lparam_done(teco_machine_main_t *ctx, const teco_string_t * sptr_t lParam = 0; -#ifdef HAVE_LEXILLA - if (ctx->scintilla.iMessage == SCI_SETILEXER) { + if (ctx->scintilla.iMessage == SCI_NAMEOFSTYLE) { + /* + * FIXME: This customized version of SCI_NAMEOFSTYLE could be avoided + * if we had a way to call Scintilla messages that return strings into + * Q-Registers. + */ if (teco_string_contains(str, '\0')) { g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, - "Lexer name must not contain null-byte."); + "Style name must not contain null-byte."); return NULL; } - const gchar *lexer = str->data ? : ""; - lParam = (sptr_t)CreateLexer(lexer); + /* + * FIXME: Should we cache the name to style id? + */ + guint count = teco_interface_ssm(SCI_GETNAMEDSTYLES, 0, 0); + for (guint id = 0; id < count; id++) { + gchar style[128] = ""; + teco_interface_ssm(SCI_NAMEOFSTYLE, id, (sptr_t)style); + if (!teco_string_cmp(str, style, strlen(style))) { + teco_expressions_push(id); + return &teco_state_start; + } + } + + g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED, + "Style name \"%s\" not found.", str->data ? : ""); + return NULL; + } +#ifdef HAVE_LEXILLA + else if (ctx->scintilla.iMessage == SCI_SETILEXER) { + CreateLexerFn CreateLexerFn = CreateLexer; + + const gchar *lexer = memchr(str->data ? : "", '\0', str->len); + if (lexer) { + /* external lexer */ + lexer++; + + /* + * NOTE: The same module can be opened multiple times. + * They are internally reference counted. + */ + GModule *module = g_module_open(str->data, G_MODULE_BIND_LAZY); + if (!module) { + teco_error_module_set(error, "Error opening lexer module"); + return NULL; + } + + GetNameSpaceFn GetNameSpaceFn; + SetLibraryPropertyFn SetLibraryPropertyFn; + + if (!g_module_symbol(module, LEXILLA_GETNAMESPACE, (gpointer *)&GetNameSpaceFn) || + !g_module_symbol(module, LEXILLA_SETLIBRARYPROPERTY, (gpointer *)&SetLibraryPropertyFn) || + !g_module_symbol(module, LEXILLA_CREATELEXER, (gpointer *)&CreateLexerFn)) { + teco_error_module_set(error, "Cannot find lexer function"); + return NULL; + } + + if (!g_strcmp0(GetNameSpaceFn(), "scintillua")) { + /* + * Scintillua's lexer directory must be configured before calling CreateLexer(). + * + * FIXME: In Scintillua distributions, the lexers are usually contained in the + * same directory as the prebuilt shared libraries. + * Perhaps we should default scintillua.lexers to the dirname in str->data? + */ + teco_qreg_t *reg = teco_qreg_table_find(&teco_qreg_table_globals, "$SCITECO_SCINTILLUA_LEXERS", 26); + if (reg) { + teco_string_t dir; + if (!reg->vtable->get_string(reg, &dir.data, &dir.len, NULL, error)) + return NULL; + SetLibraryPropertyFn("scintillua.lexers", dir.data ? : ""); + } + } + } else { + /* Lexilla lexer */ + lexer = str->data ? : ""; + } + + lParam = (sptr_t)CreateLexerFn(lexer); if (!lParam) { g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED, - "Lexilla lexer \"%s\" not found.", lexer); + "Lexer \"%s\" not found.", lexer); return NULL; } - } else + } #endif - if (str->len > 0) { + else if (str->len > 0) { /* * NOTE: There may even be messages that read strings * with embedded nulls. |