diff options
-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. |